summaryrefslogtreecommitdiffstats
path: root/layout/base/tests/chrome
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /layout/base/tests/chrome
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'layout/base/tests/chrome')
-rw-r--r--layout/base/tests/chrome/animated.gifbin0 -> 527 bytes
-rw-r--r--layout/base/tests/chrome/blue-32x32.pngbin0 -> 110 bytes
-rw-r--r--layout/base/tests/chrome/bug1041200_frame.html2
-rw-r--r--layout/base/tests/chrome/bug1041200_window.html40
-rw-r--r--layout/base/tests/chrome/bug1722890.html18
-rw-r--r--layout/base/tests/chrome/bug1722890_ref.html19
-rw-r--r--layout/base/tests/chrome/bug1769161_1.html17
-rw-r--r--layout/base/tests/chrome/bug1769161_1_ref.html17
-rw-r--r--layout/base/tests/chrome/bug1769161_2.html17
-rw-r--r--layout/base/tests/chrome/bug1769161_2_ref.html17
-rw-r--r--layout/base/tests/chrome/bug1769161_3.html17
-rw-r--r--layout/base/tests/chrome/bug1769161_3_ref.html18
-rw-r--r--layout/base/tests/chrome/bug1769161_4.html17
-rw-r--r--layout/base/tests/chrome/bug1769161_4_ref.html18
-rw-r--r--layout/base/tests/chrome/bug495648.rdf214
-rw-r--r--layout/base/tests/chrome/bug551434_childframe.html4
-rw-r--r--layout/base/tests/chrome/chrome.toml167
-rw-r--r--layout/base/tests/chrome/chrome_content_integration_window.xhtml45
-rw-r--r--layout/base/tests/chrome/color_adjust.html9
-rw-r--r--layout/base/tests/chrome/color_adjust_ref.html8
-rw-r--r--layout/base/tests/chrome/default_background_window.xhtml67
-rw-r--r--layout/base/tests/chrome/dialog_with_positioning_window.xhtml30
-rw-r--r--layout/base/tests/chrome/file_bug1018265.xhtml50
-rw-r--r--layout/base/tests/chrome/file_bug458898.html1
-rw-r--r--layout/base/tests/chrome/file_bug465448.html1
-rw-r--r--layout/base/tests/chrome/frame_css_visibility_propagation.html1
-rw-r--r--layout/base/tests/chrome/green.pngbin0 -> 91 bytes
-rw-r--r--layout/base/tests/chrome/markA.ttfbin0 -> 1568 bytes
-rw-r--r--layout/base/tests/chrome/markB.ttfbin0 -> 1568 bytes
-rw-r--r--layout/base/tests/chrome/print_page_size1.html31
-rw-r--r--layout/base/tests/chrome/print_page_size1_ref.html31
-rw-r--r--layout/base/tests/chrome/print_page_size2.html31
-rw-r--r--layout/base/tests/chrome/print_page_size2_ref.html34
-rw-r--r--layout/base/tests/chrome/print_page_size3.html31
-rw-r--r--layout/base/tests/chrome/print_page_size3_ref.html33
-rw-r--r--layout/base/tests/chrome/print_page_size4.html31
-rw-r--r--layout/base/tests/chrome/print_page_size4_ref.html31
-rw-r--r--layout/base/tests/chrome/printpreview_bug1713404_ref.html27
-rw-r--r--layout/base/tests/chrome/printpreview_bug1730091_ref.html27
-rw-r--r--layout/base/tests/chrome/printpreview_bug396024_helper.xhtml96
-rw-r--r--layout/base/tests/chrome/printpreview_bug482976_helper.xhtml50
-rw-r--r--layout/base/tests/chrome/printpreview_downloadable_font.html24
-rw-r--r--layout/base/tests/chrome/printpreview_downloadable_font_in_iframe.html25
-rw-r--r--layout/base/tests/chrome/printpreview_downloadable_font_in_iframe_ref.html24
-rw-r--r--layout/base/tests/chrome/printpreview_downloadable_font_ref.html23
-rw-r--r--layout/base/tests/chrome/printpreview_font_api.html25
-rw-r--r--layout/base/tests/chrome/printpreview_font_api_ref.html23
-rw-r--r--layout/base/tests/chrome/printpreview_font_mozprintcallback.html27
-rw-r--r--layout/base/tests/chrome/printpreview_font_mozprintcallback_ref.html28
-rw-r--r--layout/base/tests/chrome/printpreview_helper.xhtml1721
-rw-r--r--layout/base/tests/chrome/printpreview_image_select.html7
-rw-r--r--layout/base/tests/chrome/printpreview_image_select_ref.html4
-rw-r--r--layout/base/tests/chrome/printpreview_images.html25
-rw-r--r--layout/base/tests/chrome/printpreview_images_ref.html15
-rw-r--r--layout/base/tests/chrome/printpreview_images_sw.html46
-rw-r--r--layout/base/tests/chrome/printpreview_images_sw.js11
-rw-r--r--layout/base/tests/chrome/printpreview_images_sw_ref.html14
-rw-r--r--layout/base/tests/chrome/printpreview_mask.html16
-rw-r--r--layout/base/tests/chrome/printpreview_mixed_page_size_001.html11
-rw-r--r--layout/base/tests/chrome/printpreview_mixed_page_size_002.html15
-rw-r--r--layout/base/tests/chrome/printpreview_pps16.html43
-rw-r--r--layout/base/tests/chrome/printpreview_pps16_ref.html49
-rw-r--r--layout/base/tests/chrome/printpreview_pps2.html15
-rw-r--r--layout/base/tests/chrome/printpreview_pps2_ref.html40
-rw-r--r--layout/base/tests/chrome/printpreview_pps4.html19
-rw-r--r--layout/base/tests/chrome/printpreview_pps4_ref.html25
-rw-r--r--layout/base/tests/chrome/printpreview_pps6.html40
-rw-r--r--layout/base/tests/chrome/printpreview_pps6_ref.html90
-rw-r--r--layout/base/tests/chrome/printpreview_pps9.html29
-rw-r--r--layout/base/tests/chrome/printpreview_pps9_ref.html40
-rw-r--r--layout/base/tests/chrome/printpreview_pps_uw2.html16
-rw-r--r--layout/base/tests/chrome/printpreview_pps_uw2_no_margin_ref.html36
-rw-r--r--layout/base/tests/chrome/printpreview_pps_uw2_ref.html49
-rw-r--r--layout/base/tests/chrome/printpreview_pps_uw4.html19
-rw-r--r--layout/base/tests/chrome/printpreview_pps_uw4_ref.html70
-rw-r--r--layout/base/tests/chrome/printpreview_pps_uw9.html29
-rw-r--r--layout/base/tests/chrome/printpreview_pps_uw9_ref.html82
-rw-r--r--layout/base/tests/chrome/printpreview_prettyprint.xml1
-rw-r--r--layout/base/tests/chrome/printpreview_prettyprint_ref.xhtml3
-rw-r--r--layout/base/tests/chrome/printpreview_quirks.html8
-rw-r--r--layout/base/tests/chrome/printpreview_quirks_ref.html5
-rw-r--r--layout/base/tests/chrome/red.pngbin0 -> 510 bytes
-rw-r--r--layout/base/tests/chrome/test_bug1018265.xhtml37
-rw-r--r--layout/base/tests/chrome/test_bug1041200.xhtml22
-rw-r--r--layout/base/tests/chrome/test_bug396367-1.html40
-rw-r--r--layout/base/tests/chrome/test_bug396367-2.html47
-rw-r--r--layout/base/tests/chrome/test_bug420499.xhtml126
-rw-r--r--layout/base/tests/chrome/test_bug458898.html39
-rw-r--r--layout/base/tests/chrome/test_bug465448.xhtml45
-rw-r--r--layout/base/tests/chrome/test_bug514660.xhtml35
-rw-r--r--layout/base/tests/chrome/test_bug533845.xhtml49
-rw-r--r--layout/base/tests/chrome/test_bug551434.html95
-rw-r--r--layout/base/tests/chrome/test_bug708062.html43
-rw-r--r--layout/base/tests/chrome/test_bug812817.xhtml37
-rw-r--r--layout/base/tests/chrome/test_chrome_content_integration.xhtml24
-rw-r--r--layout/base/tests/chrome/test_color_scheme_browser.xhtml145
-rw-r--r--layout/base/tests/chrome/test_css_visibility_propagation.xhtml209
-rw-r--r--layout/base/tests/chrome/test_default_background.xhtml22
-rw-r--r--layout/base/tests/chrome/test_dialog_with_positioning.html20
-rw-r--r--layout/base/tests/chrome/test_document_adopted_styles.html8
-rw-r--r--layout/base/tests/chrome/test_document_adopted_styles_ref.html6
-rw-r--r--layout/base/tests/chrome/test_fixed_bg_scrolling_repaints.html40
-rw-r--r--layout/base/tests/chrome/test_getClientRectsAndTexts.html80
-rw-r--r--layout/base/tests/chrome/test_get_printer_basic_attributes.html36
-rw-r--r--layout/base/tests/chrome/test_get_printer_orientation.html50
-rw-r--r--layout/base/tests/chrome/test_get_printer_paper_sizes.html69
-rw-r--r--layout/base/tests/chrome/test_prerendered_transforms.html46
-rw-r--r--layout/base/tests/chrome/test_printer_default_settings.html63
-rw-r--r--layout/base/tests/chrome/test_printpreview.xhtml16
-rw-r--r--layout/base/tests/chrome/test_printpreview_bug396024.xhtml21
-rw-r--r--layout/base/tests/chrome/test_printpreview_bug482976.xhtml21
-rw-r--r--layout/base/tests/chrome/test_scrolling_repaints.html48
-rw-r--r--layout/base/tests/chrome/test_shadow_root_adopted_styles.html11
-rw-r--r--layout/base/tests/chrome/test_shadow_root_adopted_styles_ref.html11
-rw-r--r--layout/base/tests/chrome/test_shared_adopted_styles.html19
-rw-r--r--layout/base/tests/chrome/test_shared_adopted_styles_ref.html16
-rw-r--r--layout/base/tests/chrome/test_will_change.html140
-rw-r--r--layout/base/tests/chrome/window_css_visibility_propagation-1.xhtml6
-rw-r--r--layout/base/tests/chrome/window_css_visibility_propagation-2.xhtml6
-rw-r--r--layout/base/tests/chrome/window_css_visibility_propagation-3.html3
-rw-r--r--layout/base/tests/chrome/window_css_visibility_propagation-4.html3
121 files changed, 5813 insertions, 0 deletions
diff --git a/layout/base/tests/chrome/animated.gif b/layout/base/tests/chrome/animated.gif
new file mode 100644
index 0000000000..b2895487bd
--- /dev/null
+++ b/layout/base/tests/chrome/animated.gif
Binary files differ
diff --git a/layout/base/tests/chrome/blue-32x32.png b/layout/base/tests/chrome/blue-32x32.png
new file mode 100644
index 0000000000..deefd19b2a
--- /dev/null
+++ b/layout/base/tests/chrome/blue-32x32.png
Binary files differ
diff --git a/layout/base/tests/chrome/bug1041200_frame.html b/layout/base/tests/chrome/bug1041200_frame.html
new file mode 100644
index 0000000000..0030ec0edd
--- /dev/null
+++ b/layout/base/tests/chrome/bug1041200_frame.html
@@ -0,0 +1,2 @@
+<body onload='parent.childLoaded()' style='background:lime'>
+<p>Hello<p>Hello<p>Hello<p>Hello<p>Hello<p>
diff --git a/layout/base/tests/chrome/bug1041200_window.html b/layout/base/tests/chrome/bug1041200_window.html
new file mode 100644
index 0000000000..005f7bcd13
--- /dev/null
+++ b/layout/base/tests/chrome/bug1041200_window.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 1041200</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"></script>
+</head>
+<body>
+<iframe style="width:700px; height:500px; margin-top:200px;" id="ourFrame"></iframe>
+<script>
+var SpecialPowers = window.arguments[0].SpecialPowers;
+var SimpleTest = window.arguments[0].SimpleTest;
+var ok = window.arguments[0].ok;
+var info = window.arguments[0].info;
+
+var viewer = SpecialPowers.setFullZoom(window, 2);
+
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function() {
+ window.waitForAllPaintsFlushed(function () {
+ // Supply random key to ensure load actually happens
+ ourFrame.src = "bug1041200_frame.html?" + Math.random();
+ }, document.getElementById("ourFrame").contentDocument);
+};
+
+window.childLoaded = function() {
+ setTimeout(function() {
+ window.waitForAllPaintsFlushed(function(x1, y1, x2, y2) {
+ // We set the full zoom of this window too, so we need to account for it here.
+ ok(x2 - x1 >= 700 / 2 && y2 - y1 >= 500 / 2,
+ "expected to see invalidate of entire frame, got " + [x1,y1,x2,y2].join(','));
+ SimpleTest.finish();
+ window.close();
+ });
+ }, 0);
+};
+</script>
+
diff --git a/layout/base/tests/chrome/bug1722890.html b/layout/base/tests/chrome/bug1722890.html
new file mode 100644
index 0000000000..76175eb33d
--- /dev/null
+++ b/layout/base/tests/chrome/bug1722890.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+div {
+ position: fixed;
+ width: 20px;
+ height: 20px;
+ background: blue;
+ left: 0;
+}
+ </style>
+ </head>
+ <body>
+ <div style="top:0"></div>
+ <div style="bottom:0"></div>
+ </body>
+</html>
diff --git a/layout/base/tests/chrome/bug1722890_ref.html b/layout/base/tests/chrome/bug1722890_ref.html
new file mode 100644
index 0000000000..8bf8e39713
--- /dev/null
+++ b/layout/base/tests/chrome/bug1722890_ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+div {
+ position: fixed;
+ width: 10px;
+ height: 10px;
+ background: blue;
+ left: 0;
+}
+ </style>
+ </head>
+ <body>
+ <div style="top:0"></div>
+ <div style="bottom:0"></div>
+ </body>
+</html>
+
diff --git a/layout/base/tests/chrome/bug1769161_1.html b/layout/base/tests/chrome/bug1769161_1.html
new file mode 100644
index 0000000000..b1cc3b6ded
--- /dev/null
+++ b/layout/base/tests/chrome/bug1769161_1.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 1in;
+ height: 1in;
+ background-color: blue;
+}
+body {
+ margin: 0;
+}
+@page {
+ size: 20in;
+}
+</style>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/bug1769161_1_ref.html b/layout/base/tests/chrome/bug1769161_1_ref.html
new file mode 100644
index 0000000000..ab56d8d045
--- /dev/null
+++ b/layout/base/tests/chrome/bug1769161_1_ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 0.5in;
+ height: 0.5in;
+ background-color: blue;
+}
+body {
+ margin: 0;
+}
+@page {
+ size: 10in;
+}
+</style>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/bug1769161_2.html b/layout/base/tests/chrome/bug1769161_2.html
new file mode 100644
index 0000000000..7728d0bd95
--- /dev/null
+++ b/layout/base/tests/chrome/bug1769161_2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 2in;
+ height: 2in;
+ background-color: blue;
+}
+body {
+ margin: 0;
+}
+@page {
+ size: 10in;
+}
+</style>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/bug1769161_2_ref.html b/layout/base/tests/chrome/bug1769161_2_ref.html
new file mode 100644
index 0000000000..3916e26a17
--- /dev/null
+++ b/layout/base/tests/chrome/bug1769161_2_ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 10in;
+ height: 10in;
+ background-color: blue;
+}
+body {
+ margin: 0;
+}
+@page {
+ size: 50in;
+}
+</style>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/bug1769161_3.html b/layout/base/tests/chrome/bug1769161_3.html
new file mode 100644
index 0000000000..b1cc3b6ded
--- /dev/null
+++ b/layout/base/tests/chrome/bug1769161_3.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 1in;
+ height: 1in;
+ background-color: blue;
+}
+body {
+ margin: 0;
+}
+@page {
+ size: 20in;
+}
+</style>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/bug1769161_3_ref.html b/layout/base/tests/chrome/bug1769161_3_ref.html
new file mode 100644
index 0000000000..b786e1ad2b
--- /dev/null
+++ b/layout/base/tests/chrome/bug1769161_3_ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 0.5in;
+ height: 0.5in;
+ background-color: blue;
+}
+body {
+ margin: 0;
+}
+@page {
+ size: 10in;
+ margin: 2in;
+}
+</style>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/bug1769161_4.html b/layout/base/tests/chrome/bug1769161_4.html
new file mode 100644
index 0000000000..7728d0bd95
--- /dev/null
+++ b/layout/base/tests/chrome/bug1769161_4.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 2in;
+ height: 2in;
+ background-color: blue;
+}
+body {
+ margin: 0;
+}
+@page {
+ size: 10in;
+}
+</style>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/bug1769161_4_ref.html b/layout/base/tests/chrome/bug1769161_4_ref.html
new file mode 100644
index 0000000000..be2de41058
--- /dev/null
+++ b/layout/base/tests/chrome/bug1769161_4_ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 10in;
+ height: 10in;
+ background-color: blue;
+}
+body {
+ margin: 0;
+}
+@page {
+ size: 50in;
+ margin: 10in;
+}
+</style>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/bug495648.rdf b/layout/base/tests/chrome/bug495648.rdf
new file mode 100644
index 0000000000..b7045aa70a
--- /dev/null
+++ b/layout/base/tests/chrome/bug495648.rdf
@@ -0,0 +1,214 @@
+<?xml version="1.0"?>
+<RDF:RDF xmlns:NS1="http://sitedelta.schierla.de/SD-rdf#"
+ xmlns:NC="http://home.netscape.com/NC-rdf#"
+ xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=19&amp;btnG=Suche&amp;meta="
+ NC:name="19 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Bag RDF:about="urn:root:bag">
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=1&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=2&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=3&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=4&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=5&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=6&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=7&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=8&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=9&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=10&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=11&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=12&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=13&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=14&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=15&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=16&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=17&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=18&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=19&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=20&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=21&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=22&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=23&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=24&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=25&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=26&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=27&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=28&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=29&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=30&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=31&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=32&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=33&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=34&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=35&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=36&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=37&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=38&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=39&amp;btnG=Suche&amp;meta="/>
+ <RDF:li RDF:resource="http://www.google.de/search?hl=de&amp;q=40&amp;btnG=Suche&amp;meta="/>
+ </RDF:Bag>
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=2&amp;btnG=Suche&amp;meta="
+ NC:name="2 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=12&amp;btnG=Suche&amp;meta="
+ NC:name="12 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=5&amp;btnG=Suche&amp;meta="
+ NC:name="5 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=6&amp;btnG=Suche&amp;meta="
+ NC:name="6 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=22&amp;btnG=Suche&amp;meta="
+ NC:name="22 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=17&amp;btnG=Suche&amp;meta="
+ NC:name="17 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="urn:root">
+ <NC:links RDF:resource="urn:root:bag"/>
+ </RDF:Description>
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=8&amp;btnG=Suche&amp;meta="
+ NC:name="8 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=1&amp;btnG=Suche&amp;meta="
+ NC:name="1 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=16&amp;btnG=Suche&amp;meta="
+ NC:name="16 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=21&amp;btnG=Suche&amp;meta="
+ NC:name="21 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=20&amp;btnG=Suche&amp;meta="
+ NC:name="20 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=9&amp;btnG=Suche&amp;meta="
+ NC:name="9 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=11&amp;btnG=Suche&amp;meta="
+ NC:name="11 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=14&amp;btnG=Suche&amp;meta="
+ NC:name="14 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=23&amp;btnG=Suche&amp;meta="
+ NC:name="23 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=24&amp;btnG=Suche&amp;meta="
+ NC:name="24 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=18&amp;btnG=Suche&amp;meta="
+ NC:name="18 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www0.pafnet.de/user/322033"
+ NC:name="pafnet - You2_xD"
+ NS1:nextScan="1243707104073"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=3&amp;btnG=Suche&amp;meta="
+ NC:name="3 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=7&amp;btnG=Suche&amp;meta="
+ NC:name="7 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=15&amp;btnG=Suche&amp;meta="
+ NC:name="15 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=4&amp;btnG=Suche&amp;meta="
+ NC:name="4 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=13&amp;btnG=Suche&amp;meta="
+ NC:name="13 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=10&amp;btnG=Suche&amp;meta="
+ NC:name="10 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=25&amp;btnG=Suche&amp;meta="
+ NC:name="25 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=26&amp;btnG=Suche&amp;meta="
+ NC:name="26 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=27&amp;btnG=Suche&amp;meta="
+ NC:name="27 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=28&amp;btnG=Suche&amp;meta="
+ NC:name="28 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=29&amp;btnG=Suche&amp;meta="
+ NC:name="29 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=30&amp;btnG=Suche&amp;meta="
+ NC:name="30 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=31&amp;btnG=Suche&amp;meta="
+ NC:name="31 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=32&amp;btnG=Suche&amp;meta="
+ NC:name="32 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=33&amp;btnG=Suche&amp;meta="
+ NC:name="33 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=34&amp;btnG=Suche&amp;meta="
+ NC:name="34 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=35&amp;btnG=Suche&amp;meta="
+ NC:name="35 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=36&amp;btnG=Suche&amp;meta="
+ NC:name="36 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=37&amp;btnG=Suche&amp;meta="
+ NC:name="37 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=38&amp;btnG=Suche&amp;meta="
+ NC:name="38 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=39&amp;btnG=Suche&amp;meta="
+ NC:name="39 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+ <RDF:Description RDF:about="http://www.google.de/search?hl=de&amp;q=40&amp;btnG=Suche&amp;meta="
+ NC:name="40 - Google-Suche"
+ NS1:nextScan="0"
+ NS1:status="0" />
+</RDF:RDF>
diff --git a/layout/base/tests/chrome/bug551434_childframe.html b/layout/base/tests/chrome/bug551434_childframe.html
new file mode 100644
index 0000000000..3d7bd6c13a
--- /dev/null
+++ b/layout/base/tests/chrome/bug551434_childframe.html
@@ -0,0 +1,4 @@
+<script>
+var gKeyDownChild = 0, gKeyPressChild = 0, gKeyUpChild = 0;
+</script>
+<input id='i4' onkeydown="gKeyDownChild++" onkeypress="gKeyPressChild++" onkeyup="gKeyUpChild++; this.parentNode.removeChild(this);">
diff --git a/layout/base/tests/chrome/chrome.toml b/layout/base/tests/chrome/chrome.toml
new file mode 100644
index 0000000000..6636b224e6
--- /dev/null
+++ b/layout/base/tests/chrome/chrome.toml
@@ -0,0 +1,167 @@
+[DEFAULT]
+prefs = [
+ "dom.window.sizeToContent.enabled=true",
+ "layout.css.individual-transform.enabled=true",
+]
+skip-if = ["os == 'android'"]
+support-files = [
+ "animated.gif",
+ "blue-32x32.png",
+ "bug1722890.html",
+ "bug1722890_ref.html",
+ "bug1769161_1.html",
+ "bug1769161_1_ref.html",
+ "bug1769161_2.html",
+ "bug1769161_2_ref.html",
+ "bug1769161_3.html",
+ "bug1769161_3_ref.html",
+ "bug1769161_4.html",
+ "bug1769161_4_ref.html",
+ "bug551434_childframe.html",
+ "chrome_content_integration_window.xhtml",
+ "default_background_window.xhtml",
+ "dialog_with_positioning_window.xhtml",
+ "file_bug458898.html",
+ "green.png",
+ "printpreview_bug1713404_ref.html",
+ "printpreview_bug1730091_ref.html",
+ "printpreview_bug396024_helper.xhtml",
+ "printpreview_bug482976_helper.xhtml",
+ "printpreview_helper.xhtml",
+ "printpreview_downloadable_font.html",
+ "printpreview_downloadable_font_ref.html",
+ "printpreview_downloadable_font_in_iframe.html",
+ "printpreview_downloadable_font_in_iframe_ref.html",
+ "printpreview_font_api.html",
+ "printpreview_font_api_ref.html",
+ "printpreview_font_mozprintcallback.html",
+ "printpreview_font_mozprintcallback_ref.html",
+ "printpreview_quirks.html",
+ "printpreview_quirks_ref.html",
+ "printpreview_images.html",
+ "printpreview_images_ref.html",
+ "printpreview_images_sw.html",
+ "printpreview_images_sw_ref.html",
+ "printpreview_images_sw.js",
+ "printpreview_image_select.html",
+ "printpreview_image_select_ref.html",
+ "printpreview_mixed_page_size_001.html",
+ "printpreview_mixed_page_size_002.html",
+ "printpreview_pps_uw2.html",
+ "printpreview_pps_uw2_ref.html",
+ "printpreview_pps_uw2_no_margin_ref.html",
+ "printpreview_pps_uw4.html",
+ "printpreview_pps_uw4_ref.html",
+ "printpreview_pps_uw9.html",
+ "printpreview_pps_uw9_ref.html",
+ "printpreview_pps2.html",
+ "printpreview_pps2_ref.html",
+ "printpreview_pps4.html",
+ "printpreview_pps4_ref.html",
+ "printpreview_pps6.html",
+ "printpreview_pps6_ref.html",
+ "printpreview_pps9.html",
+ "printpreview_pps9_ref.html",
+ "printpreview_pps16.html",
+ "printpreview_pps16_ref.html",
+ "printpreview_prettyprint.xml",
+ "printpreview_prettyprint_ref.xhtml",
+ "printpreview_mask.html",
+ "print_page_size1.html",
+ "print_page_size1_ref.html",
+ "print_page_size2.html",
+ "print_page_size2_ref.html",
+ "print_page_size3.html",
+ "print_page_size3_ref.html",
+ "print_page_size4.html",
+ "print_page_size4_ref.html",
+ "red.png",
+ "color_adjust.html",
+ "color_adjust_ref.html",
+ "test_document_adopted_styles.html",
+ "test_document_adopted_styles_ref.html",
+ "test_shadow_root_adopted_styles.html",
+ "test_shadow_root_adopted_styles_ref.html",
+ "test_shared_adopted_styles.html",
+ "test_shared_adopted_styles_ref.html",
+ "file_bug1018265.xhtml",
+ "markA.ttf",
+ "markB.ttf",
+]
+
+["test_bug396367-1.html"]
+
+["test_bug396367-2.html"]
+
+["test_bug420499.xhtml"]
+
+["test_bug458898.html"]
+
+["test_bug465448.xhtml"]
+support-files = ["file_bug465448.html"]
+
+["test_bug514660.xhtml"]
+
+["test_bug533845.xhtml"]
+skip-if = ["os == 'linux' && !debug"] # Bug 1208197
+
+["test_bug551434.html"]
+
+["test_bug708062.html"]
+
+["test_bug812817.xhtml"]
+
+["test_bug1018265.xhtml"]
+
+["test_bug1041200.xhtml"]
+skip-if = ["os == 'win' && bits == 64"] # Bug 1272321
+support-files = [
+ "bug1041200_frame.html",
+ "bug1041200_window.html",
+]
+
+["test_chrome_content_integration.xhtml"]
+
+["test_color_scheme_browser.xhtml"]
+
+["test_css_visibility_propagation.xhtml"]
+support-files = [
+ "window_css_visibility_propagation-1.xhtml",
+ "window_css_visibility_propagation-2.xhtml",
+ "window_css_visibility_propagation-3.html",
+ "window_css_visibility_propagation-4.html",
+ "frame_css_visibility_propagation.html",
+]
+
+["test_default_background.xhtml"]
+
+["test_dialog_with_positioning.html"]
+tags = "openwindow"
+
+["test_fixed_bg_scrolling_repaints.html"]
+
+["test_getClientRectsAndTexts.html"]
+
+["test_get_printer_basic_attributes.html"]
+
+["test_get_printer_orientation.html"]
+
+["test_get_printer_paper_sizes.html"]
+
+["test_prerendered_transforms.html"]
+
+["test_printer_default_settings.html"]
+
+["test_printpreview.xhtml"]
+skip-if = ["verify && os == 'win'"]
+
+["test_printpreview_bug396024.xhtml"]
+skip-if = ["verify && os == 'win'"]
+
+["test_printpreview_bug482976.xhtml"]
+skip-if = ["verify && os == 'win'"]
+
+["test_scrolling_repaints.html"]
+
+["test_will_change.html"]
+skip-if = ["true"]
diff --git a/layout/base/tests/chrome/chrome_content_integration_window.xhtml b/layout/base/tests/chrome/chrome_content_integration_window.xhtml
new file mode 100644
index 0000000000..1dd1b7f882
--- /dev/null
+++ b/layout/base/tests/chrome/chrome_content_integration_window.xhtml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<window title="Content/chrome integration subwindow"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="runTests()"
+ style="background:black; -moz-appearance:none;">
+ <script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+
+ <stack style="align-items: center; height: 300px; width: 200px;">
+ <!-- the bottom 100px is a strip of black that should be visible through the content iframe -->
+ <vbox style="background:pink; border-bottom:100px solid black"/>
+ <!-- the middle 100px is a strip of black in the content iframe -->
+ <!-- the bottom 100px of the iframe is transparent, the top 100px is yellow -->
+ <iframe type="content" style="border:none; width: 10px; height: 10px;"
+ transparent="transparent"
+ src="data:text/html,&lt;div style='position:absolute;left:0;top:0;width:100%;height:100px;background:yellow;border-bottom:100px solid black'&gt;"/>
+ <!-- the top 100px is a strip of black above the content iframe -->
+ <vbox style="border-top:100px solid black;"/>
+ </stack>
+
+ <script type="application/javascript">
+ <![CDATA[
+ var imports = [ "SimpleTest", "is", "isnot", "ok", "SpecialPowers" ];
+ for (var name of imports) {
+ window[name] = window.arguments[0][name];
+ }
+
+ function runTests() {
+ var testCanvas = snapshotWindow(window);
+
+ var refCanvas = snapshotWindow(window);
+ var ctx = refCanvas.getContext('2d');
+ ctx.fillStyle = "black";
+ ctx.fillRect(0, 0, refCanvas.width, refCanvas.height);
+
+ var comparison = compareSnapshots(testCanvas, refCanvas, true);
+ ok(comparison[0], "Rendering OK, got " + comparison[1] + ", expected " + comparison[2]);
+
+ var tester = window.SimpleTest;
+ window.close();
+ tester.finish();
+ }
+ ]]>
+ </script>
+</window>
diff --git a/layout/base/tests/chrome/color_adjust.html b/layout/base/tests/chrome/color_adjust.html
new file mode 100644
index 0000000000..4a9846e28d
--- /dev/null
+++ b/layout/base/tests/chrome/color_adjust.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<style>
+.test {
+ background-color: black;
+ color: white;
+ color-adjust: exact;
+}
+</style>
+<span class="test">Some text goes here</span>
diff --git a/layout/base/tests/chrome/color_adjust_ref.html b/layout/base/tests/chrome/color_adjust_ref.html
new file mode 100644
index 0000000000..f5986f93bf
--- /dev/null
+++ b/layout/base/tests/chrome/color_adjust_ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<style>
+.test {
+ background-color: black;
+ color: white;
+}
+</style>
+<span class="test">Some text goes here</span>
diff --git a/layout/base/tests/chrome/default_background_window.xhtml b/layout/base/tests/chrome/default_background_window.xhtml
new file mode 100644
index 0000000000..4bc49c0f36
--- /dev/null
+++ b/layout/base/tests/chrome/default_background_window.xhtml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="runTests()">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+
+ <iframe type="content" id="f" src="about:blank" style="border:1px solid black;"/>
+
+ <script>
+ <![CDATA[
+ SimpleTest.waitForExplicitFinish();
+
+ var imports = [ "SimpleTest", "is", "isnot", "ok" ];
+ for (var name of imports) {
+ window[name] = window.arguments[0][name];
+ }
+
+ function snapshot(win) {
+ var el = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+ el.width = win.innerWidth;
+ el.height = win.innerHeight;
+
+ var ctx = el.getContext("2d");
+ ctx.drawWindow(win, 0, 0,
+ win.innerWidth, win.innerHeight,
+ "rgba(0,0,0,0)", 0);
+ return el;
+ }
+
+ var color = '#2468AC';
+ var prefs = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefBranch);
+ var backgroundPref = matchMedia('(prefers-color-scheme:dark)').matches
+ ? 'browser.display.background_color.dark'
+ : 'browser.display.background_color';
+ prefs.setCharPref(backgroundPref, color);
+ // On Windows, this preference is true by default, we make it
+ // false to ensure we're using the color set above for our reference.
+ prefs.setBoolPref('browser.display.use_system_colors', false);
+
+ function runTests() {
+ var f = document.getElementById("f");
+
+ var testCanvas = snapshot(f.contentWindow);
+ prefs.clearUserPref(backgroundPref);
+ // Reset sys colors pref so we're using the system color for our test.
+ prefs.clearUserPref('browser.display.use_system_colors');
+
+ var refCanvas = snapshot(f.contentWindow);
+ var ctx = refCanvas.getContext('2d');
+ ctx.fillStyle = color;
+ ctx.fillRect(0, 0, refCanvas.width, refCanvas.height);
+
+ var comparison = compareSnapshots(testCanvas, refCanvas, true);
+ ok(comparison[0], "Rendering OK, got " + comparison[1] + ", expected " + comparison[2]);
+
+
+ var tester = window.SimpleTest;
+ window.close();
+ tester.finish();
+ }
+ ]]>
+ </script>
+</window>
diff --git a/layout/base/tests/chrome/dialog_with_positioning_window.xhtml b/layout/base/tests/chrome/dialog_with_positioning_window.xhtml
new file mode 100644
index 0000000000..a854248b21
--- /dev/null
+++ b/layout/base/tests/chrome/dialog_with_positioning_window.xhtml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="setTimeout(runTest, 0)">
+ <vbox>
+ <label value="powered by example.com" style="padding: 16px;"/>
+ </vbox>
+ <hbox id="t" style="display: block; position: fixed; right: 16px; bottom: 16px;">
+ <button label="OK"/>
+ </hbox>
+<script><![CDATA[
+var SimpleTest = window.arguments[0].SimpleTest;
+var SpecialPowers = window.arguments[0].SpecialPowers;
+var is = window.arguments[0].is;
+var ok = window.arguments[0].ok;
+
+// We run this off a setTimeout from onload, because the XUL window
+// only does its intrinsic-height layout after the load event has
+// finished
+function runTest() {
+ var t = document.getElementById("t");
+ var tBottom = t.getBoundingClientRect().bottom;
+ is(tBottom, document.documentElement.getBoundingClientRect().bottom - 16,
+ "check fixed-pos element t bottom positioned correctly");
+ ok(tBottom < 200, "fixed-pos element t bottom must be sane, less than 200 (got " + tBottom + ")");
+ window.close();
+ SimpleTest.finish();
+}
+]]></script>
+</window>
diff --git a/layout/base/tests/chrome/file_bug1018265.xhtml b/layout/base/tests/chrome/file_bug1018265.xhtml
new file mode 100644
index 0000000000..1f9be6ba97
--- /dev/null
+++ b/layout/base/tests/chrome/file_bug1018265.xhtml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1018265
+-->
+<window title="Mozilla Bug 1018265"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="setTimeout(run, 0);">
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 1018265 **/
+
+ var testcontent = null;
+
+ function run() {
+ testcontent = document.getElementById("testcontent");
+ shouldHaveTwoNonHiddenDocumentViewers();
+ testcontent.setAttribute("src", "foobarpage");
+ setTimeout(errorPageLoaded, 2500)
+ }
+
+ function errorPageLoaded() {
+ testcontent.addEventListener("pageshow", didGoBack, true);
+ setTimeout(function() {testcontent.contentWindow.history.back();}, 0);
+ }
+
+ function didGoBack(e) {
+ testcontent.removeEventListener("pageshow", didGoBack, true);
+ shouldHaveTwoNonHiddenDocumentViewers();
+ window.arguments[0].done();
+ window.close();
+ }
+
+ function getDocumentViewer(win) {
+ return win.docShell.docViewer;
+ }
+
+ function shouldHaveTwoNonHiddenDocumentViewers() {
+ window.arguments[0].is(getDocumentViewer(testcontent.contentWindow).isHidden, false, "Top level DocumentViewer should not be hidden.");
+ window.arguments[0].is(getDocumentViewer(testcontent.contentWindow.frames[0]).isHidden, false, " Iframe's DocumentViewer should not be hidden.");
+ }
+ ]]>
+ </script>
+
+ <browser type="content" id="testcontent" flex="1" src="data:text/html,&lt;iframe&gt;&lt;/iframe&gt;"/>
+</window>
diff --git a/layout/base/tests/chrome/file_bug458898.html b/layout/base/tests/chrome/file_bug458898.html
new file mode 100644
index 0000000000..6db840689d
--- /dev/null
+++ b/layout/base/tests/chrome/file_bug458898.html
@@ -0,0 +1 @@
+<div style='height:200px; width:100px;'>
diff --git a/layout/base/tests/chrome/file_bug465448.html b/layout/base/tests/chrome/file_bug465448.html
new file mode 100644
index 0000000000..5df5b61375
--- /dev/null
+++ b/layout/base/tests/chrome/file_bug465448.html
@@ -0,0 +1 @@
+<body onload='window.opener.loaded()'><div style='height:200px; width:100px;'>
diff --git a/layout/base/tests/chrome/frame_css_visibility_propagation.html b/layout/base/tests/chrome/frame_css_visibility_propagation.html
new file mode 100644
index 0000000000..dbb5d819d1
--- /dev/null
+++ b/layout/base/tests/chrome/frame_css_visibility_propagation.html
@@ -0,0 +1 @@
+<button id="button">Button</button>
diff --git a/layout/base/tests/chrome/green.png b/layout/base/tests/chrome/green.png
new file mode 100644
index 0000000000..25b76c3c6f
--- /dev/null
+++ b/layout/base/tests/chrome/green.png
Binary files differ
diff --git a/layout/base/tests/chrome/markA.ttf b/layout/base/tests/chrome/markA.ttf
new file mode 100644
index 0000000000..353e7ac332
--- /dev/null
+++ b/layout/base/tests/chrome/markA.ttf
Binary files differ
diff --git a/layout/base/tests/chrome/markB.ttf b/layout/base/tests/chrome/markB.ttf
new file mode 100644
index 0000000000..c683ddf945
--- /dev/null
+++ b/layout/base/tests/chrome/markB.ttf
Binary files differ
diff --git a/layout/base/tests/chrome/print_page_size1.html b/layout/base/tests/chrome/print_page_size1.html
new file mode 100644
index 0000000000..851b910f26
--- /dev/null
+++ b/layout/base/tests/chrome/print_page_size1.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+@page {
+ size: 3in;
+ margin: 0;
+}
+div {
+ position: absolute;
+ background: blue;
+ width: 20px;
+ height: 20px;
+}
+.upper {
+ top: 1in;
+}
+.lower{
+ bottom: 1.5in;
+}
+.left{
+ left: 1in;
+}
+.right{
+ right: 1.5in;
+}
+</style>
+<body>
+<div class="upper left"></div>
+<div class="upper right"></div>
+<div class="lower left"></div>
+<div class="lower right"></div>
+</body>
diff --git a/layout/base/tests/chrome/print_page_size1_ref.html b/layout/base/tests/chrome/print_page_size1_ref.html
new file mode 100644
index 0000000000..cc3ff8598f
--- /dev/null
+++ b/layout/base/tests/chrome/print_page_size1_ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+@page {
+ size: 2in;
+ margin: 0.5in;
+}
+div {
+ position: absolute;
+ background: blue;
+ width: 20px;
+ height: 20px;
+}
+.upper {
+ top: 0.5in;
+}
+.lower{
+ bottom: 0;
+}
+.left{
+ left: 0.5in;
+}
+.right{
+ right: 0;
+}
+</style>
+<body>
+<div class="upper left"></div>
+<div class="upper right"></div>
+<div class="lower left"></div>
+<div class="lower right"></div>
+</body>
diff --git a/layout/base/tests/chrome/print_page_size2.html b/layout/base/tests/chrome/print_page_size2.html
new file mode 100644
index 0000000000..d9a181576d
--- /dev/null
+++ b/layout/base/tests/chrome/print_page_size2.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+@page {
+ size: 20in 3in;
+ margin: 0;
+}
+div {
+ position: absolute;
+ background: blue;
+ width: 20px;
+ height: 20px;
+}
+.upper {
+ top: 0;
+}
+.lower{
+ bottom: 0;
+}
+.left{
+ left: 0;
+}
+.right{
+ right: 0;
+}
+</style>
+<body>
+<div class="upper left"></div>
+<div class="upper right"></div>
+<div class="lower left"></div>
+<div class="lower right"></div>
+</body>
diff --git a/layout/base/tests/chrome/print_page_size2_ref.html b/layout/base/tests/chrome/print_page_size2_ref.html
new file mode 100644
index 0000000000..0a40acc0eb
--- /dev/null
+++ b/layout/base/tests/chrome/print_page_size2_ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<style>
+@page {
+ size: 20in 5in;
+ margin: 0;
+}
+div {
+ position: absolute;
+ background: blue;
+ width: 20px;
+ height: 20px;
+}
+.upper {
+ top: 0;
+}
+.lower{
+ /* This accounts for the difference in @page{ size: ... }, as long as the
+ * page is placed aligned to the upper left corner of the paper.
+ */
+ bottom: 2in;
+}
+.left{
+ left: 0;
+}
+.right{
+ right: 0;
+}
+</style>
+<body>
+<div class="upper left"></div>
+<div class="upper right"></div>
+<div class="lower left"></div>
+<div class="lower right"></div>
+</body>
diff --git a/layout/base/tests/chrome/print_page_size3.html b/layout/base/tests/chrome/print_page_size3.html
new file mode 100644
index 0000000000..45c9709817
--- /dev/null
+++ b/layout/base/tests/chrome/print_page_size3.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+@page {
+ size: 3in;
+ margin: 0;
+}
+div {
+ position: absolute;
+ background: blue;
+ width: 1in;
+ height: 1in;
+}
+.upper {
+ top: 0in;
+}
+.lower{
+ bottom: 0in;
+}
+.left{
+ left: 0in;
+}
+.right{
+ right: 0in;
+}
+</style>
+<body>
+<div class="upper left"></div>
+<div class="upper right"></div>
+<div class="lower left"></div>
+<div class="lower right"></div>
+</body>
diff --git a/layout/base/tests/chrome/print_page_size3_ref.html b/layout/base/tests/chrome/print_page_size3_ref.html
new file mode 100644
index 0000000000..cc6f69a7ad
--- /dev/null
+++ b/layout/base/tests/chrome/print_page_size3_ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<style>
+@page {
+ margin: 0;
+}
+div {
+ position: absolute;
+ background: blue;
+ width: 1in;
+ height: 1in;
+}
+/* These positions assume the test case was placed in the upper left corner of
+ * the page, rather than being centered or scaled.
+ */
+.upper {
+ top: 0;
+}
+.lower{
+ top: 2in;
+}
+.left{
+ left: 0;
+}
+.right{
+ left: 2in;
+}
+</style>
+<body>
+<div class="upper left"></div>
+<div class="upper right"></div>
+<div class="lower left"></div>
+<div class="lower right"></div>
+</body>
diff --git a/layout/base/tests/chrome/print_page_size4.html b/layout/base/tests/chrome/print_page_size4.html
new file mode 100644
index 0000000000..ef6077e2a1
--- /dev/null
+++ b/layout/base/tests/chrome/print_page_size4.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+@page {
+ size: 10in;
+ margin: 0;
+}
+div {
+ position: absolute;
+ background: blue;
+ width: 1in;
+ height: 1in;
+}
+.upper {
+ top: 0;
+}
+.lower{
+ bottom: 0;
+}
+.left{
+ left: 0;
+}
+.right{
+ right: 0;
+}
+</style>
+<body>
+<div class="upper left"></div>
+<div class="upper right"></div>
+<div class="lower left"></div>
+<div class="lower right"></div>
+</body>
diff --git a/layout/base/tests/chrome/print_page_size4_ref.html b/layout/base/tests/chrome/print_page_size4_ref.html
new file mode 100644
index 0000000000..3d32134824
--- /dev/null
+++ b/layout/base/tests/chrome/print_page_size4_ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+@page {
+ size: 20in;
+ margin: 0;
+}
+div {
+ position: absolute;
+ background: blue;
+ width: 2in;
+ height: 2in;
+}
+.upper {
+ top: 0;
+}
+.lower{
+ bottom: 0;
+}
+.left{
+ left: 0;
+}
+.right{
+ right: 0;
+}
+</style>
+<body>
+<div class="upper left"></div>
+<div class="upper right"></div>
+<div class="lower left"></div>
+<div class="lower right"></div>
+</body>
diff --git a/layout/base/tests/chrome/printpreview_bug1713404_ref.html b/layout/base/tests/chrome/printpreview_bug1713404_ref.html
new file mode 100644
index 0000000000..a08074b8a2
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_bug1713404_ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<style>
+@page {
+ margin: 2in;
+}
+div {
+ /* The default header/footer size in Firefox. */
+ font-size: 10pt;
+ position: absolute;
+}
+.upper {
+ top: 0;
+}
+.lower{
+ bottom: 0;
+}
+.left{
+ left: 0;
+}
+.right{
+ right: 0;
+}
+</style>
+<div class="upper left">|</div>
+<div class="upper right">||</div>
+<div class="lower left">|||</div>
+<div class="lower right">||||</div>
diff --git a/layout/base/tests/chrome/printpreview_bug1730091_ref.html b/layout/base/tests/chrome/printpreview_bug1730091_ref.html
new file mode 100644
index 0000000000..ac1577b852
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_bug1730091_ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<style>
+@page{
+ margin: 0;
+}
+div {
+ /* The default header/footer size in Firefox */
+ font-size: 10pt;
+ position: absolute;
+}
+.upper {
+ top: 0;
+}
+.lower{
+ bottom: 0;
+}
+.left{
+ left: 0;
+}
+.right{
+ right: 0;
+}
+</style>
+<div class="upper left">||||</div>
+<div class="upper right">||||</div>
+<div class="lower left">||||</div>
+<div class="lower right">||||</div>
diff --git a/layout/base/tests/chrome/printpreview_bug396024_helper.xhtml b/layout/base/tests/chrome/printpreview_bug396024_helper.xhtml
new file mode 100644
index 0000000000..fa587e9746
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_bug396024_helper.xhtml
@@ -0,0 +1,96 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=396024
+-->
+<window title="Mozilla Bug 396024" onload="run()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<iframe id="i" src="about:blank" type="content"></iframe>
+<iframe src="about:blank" type="content"></iframe>
+<script type="application/javascript">
+<![CDATA[
+// Note: We can't use window.frames directly here because the type="content"
+// attributes isolate the frames into their own BrowsingContext hierarchies.
+let frameElts = document.getElementsByTagName("iframe");
+
+var is = window.arguments[0].is;
+var ok = window.arguments[0].ok;
+var todo = window.arguments[0].todo;
+var SimpleTest = window.arguments[0].SimpleTest;
+var gWbp;
+function printpreview() {
+ gWbp = frameElts[1].contentWindow.docShell.initOrReusePrintPreviewViewer();
+ let settings = Cc["@mozilla.org/gfx/printsettings-service;1"]
+ .getService(Ci.nsIPrintSettingsService).createNewPrintSettings();
+ gWbp.printPreview(settings, frameElts[0].contentWindow);
+}
+
+function exitprintpreview() {
+ frameElts[1].contentWindow.docShell.exitPrintPreview();
+}
+
+function finish() {
+ SimpleTest.finish();
+ window.close();
+}
+
+function run()
+{
+/** Test for Bug 396024 **/
+ var printService = Cc["@mozilla.org/gfx/printsettings-service;1"]
+ .getService(Ci.nsIPrintSettingsService);
+
+ if (printService.lastUsedPrinterName != '') {
+ printpreview();
+ ok(gWbp.doingPrintPreview, "Should be doing print preview");
+ exitprintpreview();
+ ok(!gWbp.doingPrintPreview, "Should not be doing print preview anymore1");
+ printpreview();
+ setTimeout(run2, 0)
+ } else {
+ todo(false, "No printer seems installed on this machine, that is necessary for this test");
+ finish();
+ }
+}
+
+function run2() {
+ var loadhandler = function() {
+ document.getElementById("i").removeEventListener("load", arguments.callee, true);
+ setTimeout(run3, 0);
+ };
+ document.getElementById("i").addEventListener("load", loadhandler, true);
+ frameElts[0].contentWindow.location.reload();
+}
+
+function run3() {
+ gWbp = frameElts[1].contentWindow.docShell.initOrReusePrintPreviewViewer();
+ ok(gWbp.doingPrintPreview, "Should be doing print preview");
+ exitprintpreview();
+ setTimeout(run4, 0);
+}
+
+function run4() {
+ var i = document.getElementById("i");
+ i.remove();
+ var loadhandler = function() {
+ document.getElementById("i").removeEventListener("load", loadhandler, true);
+ setTimeout(run5, 0);
+ };
+ i.addEventListener("load", loadhandler, true);
+ document.documentElement.getBoundingClientRect();
+ document.documentElement.prepend(i);
+}
+
+function run5() {
+ gWbp = frameElts[1].contentWindow.docShell.initOrReusePrintPreviewViewer();
+ ok(!gWbp.doingPrintPreview, "Should not be doing print preview anymore2");
+
+ //XXX this shouldn't be necessary, see bug 405555
+ printpreview();
+ exitprintpreview();
+ finish(); //should not have crashed after all of this
+}
+]]></script>
+</window>
diff --git a/layout/base/tests/chrome/printpreview_bug482976_helper.xhtml b/layout/base/tests/chrome/printpreview_bug482976_helper.xhtml
new file mode 100644
index 0000000000..81c29e1588
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_bug482976_helper.xhtml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=482976
+-->
+<window title="Mozilla Bug 482976" onload="run1()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<iframe src="about:blank" type="content"></iframe>
+<iframe src="about:blank" type="content"></iframe>
+<script type="application/javascript">
+<![CDATA[
+// Note: We can't use window.frames directly here because the type="content"
+// attributes isolate the frames into their own BrowsingContext hierarchies.
+let frameElts = document.getElementsByTagName("iframe");
+
+var is = window.arguments[0].is;
+var ok = window.arguments[0].ok;
+var todo = window.arguments[0].todo;
+var SimpleTest = window.arguments[0].SimpleTest;
+var gWbp;
+var gPrintPreviewWin;
+function printpreview() {
+ let settings = Cc["@mozilla.org/gfx/printsettings-service;1"]
+ .getService(Ci.nsIPrintSettingsService).createNewPrintSettings();
+ gPrintPreviewWin = frameElts[0].contentWindow.printPreview(settings);
+ gWbp = gPrintPreviewWin.docShell.docViewer;
+ gWbp.QueryInterface(Ci.nsIWebBrowserPrint);
+}
+
+function exitprintpreview() {
+ gPrintPreviewWin.docShell.exitPrintPreview();
+ gPrintPreviewWin.close();
+}
+
+function finish() {
+ SimpleTest.finish();
+ window.close();
+}
+
+async function run1() {
+ printpreview();
+ ok(gWbp.doingPrintPreview, "Should be doing print preview");
+ exitprintpreview();
+ ok(!gWbp.doingPrintPreview, "Should not be doing print preview anymore");
+ finish();
+}
+]]></script>
+</window>
diff --git a/layout/base/tests/chrome/printpreview_downloadable_font.html b/layout/base/tests/chrome/printpreview_downloadable_font.html
new file mode 100644
index 0000000000..6e30c55f79
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_downloadable_font.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en-US">
+<head>
+<title></title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-fonts/#font-face-rule">
+<style type="text/css">
+
+@font-face {
+ font-family: "MarkA";
+ src: url(markA.ttf);
+}
+
+body { font-family: "MarkA"; }
+
+</style>
+</head>
+<body>
+
+<p>A</p>
+
+</body>
+</html>
diff --git a/layout/base/tests/chrome/printpreview_downloadable_font_in_iframe.html b/layout/base/tests/chrome/printpreview_downloadable_font_in_iframe.html
new file mode 100644
index 0000000000..edee6ecca2
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_downloadable_font_in_iframe.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en-US">
+<head>
+<title></title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-fonts/#font-face-rule">
+</head>
+<iframe style="width:300px; height: 300px; border: 0"
+ srcdoc="<!DOCTYPE HTML>
+ <html>
+ <style>
+ @font-face {
+ font-family: 'MarkA';
+ src: url(markA.ttf);
+ }
+
+ body { font-family: 'MarkA'; }
+ </style>
+ <body>
+ <p>A</p>
+ </body>
+ </html>">
+</iframe>
+</html>
diff --git a/layout/base/tests/chrome/printpreview_downloadable_font_in_iframe_ref.html b/layout/base/tests/chrome/printpreview_downloadable_font_in_iframe_ref.html
new file mode 100644
index 0000000000..0a2a50c665
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_downloadable_font_in_iframe_ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en-US">
+<head>
+<title></title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+</head>
+<iframe style="width:300px; height: 300px; border: 0"
+ srcdoc="<!DOCTYPE HTML>
+ <html>
+ <style>
+ @font-face {
+ font-family: 'MarkB';
+ src: url(markB.ttf);
+ }
+
+ body { font-family: 'MarkB'; }
+ </style>
+ <body>
+ <p>B</p>
+ </body>
+ </html>">
+</iframe>
+</html>
diff --git a/layout/base/tests/chrome/printpreview_downloadable_font_ref.html b/layout/base/tests/chrome/printpreview_downloadable_font_ref.html
new file mode 100644
index 0000000000..5967abb5ba
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_downloadable_font_ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en-US">
+<head>
+<title></title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<style type="text/css">
+
+@font-face {
+ font-family: "MarkB";
+ src: url(markB.ttf);
+}
+
+body { font-family: "MarkB"; }
+
+</style>
+</head>
+<body>
+
+<p>B</p>
+
+</body>
+</html>
diff --git a/layout/base/tests/chrome/printpreview_font_api.html b/layout/base/tests/chrome/printpreview_font_api.html
new file mode 100644
index 0000000000..1f82d5f2d9
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_font_api.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <style type="text/css">
+ .test {
+ font-family: test, monospace;
+ }
+ </style>
+</head>
+<body>
+ <p class="test">lmnop</p>
+ <script>
+ const fontData = "data:font/opentype;base64,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";
+
+ let testFontFace = new FontFace('test', 'url(' + fontData + ')');
+ document.fonts.add(testFontFace);
+ testFontFace.loaded.then(() => {
+ window.postMessage("ready", "*");
+ }).catch((e) => {
+ window.postMessage("error", "*");
+ });
+ </script>
+</body>
+</html> \ No newline at end of file
diff --git a/layout/base/tests/chrome/printpreview_font_api_ref.html b/layout/base/tests/chrome/printpreview_font_api_ref.html
new file mode 100644
index 0000000000..61b052b4a6
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_font_api_ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <style type="text/css">
+ @font-face {
+ font-family: test;
+ src: url(data:font/opentype;base64,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);
+ }
+ .test {
+ /*
+ * Intentionally use a different fallback font than the test file so that
+ * if the font fails to load the test and reference will still be
+ * different.
+ */
+ font-family: test, sans-serif;
+ }
+ </style>
+</head>
+<body>
+ <p class="test">lmnop</p>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/printpreview_font_mozprintcallback.html b/layout/base/tests/chrome/printpreview_font_mozprintcallback.html
new file mode 100644
index 0000000000..1b4296e90a
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_font_mozprintcallback.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+ <canvas id="canvas" width="200" height="200"></canvas>
+ <script>
+ const fontData = "data:font/opentype;base64,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";
+ let canvas = document.getElementById('canvas');
+ canvas.mozPrintCallback = (obj) => {
+ let testFontFace = new FontFace('test', 'url(' + fontData + ')');
+ document.fonts.add(testFontFace);
+ testFontFace.load().then(() => {
+ let ctx = obj.context;
+ ctx.font = '10px test, monospace';
+ ctx.fillText("lmnop", 20, 20);
+ obj.done();
+ window.postMessage("ready", "*");
+ }).catch((e) => {
+ obj.done();
+ window.postMessage("error", "*");
+ });
+ };
+ </script>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/printpreview_font_mozprintcallback_ref.html b/layout/base/tests/chrome/printpreview_font_mozprintcallback_ref.html
new file mode 100644
index 0000000000..e4dd82bc58
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_font_mozprintcallback_ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <style type="text/css">
+ @font-face {
+ font-family: test;
+ src: url(data:font/opentype;base64,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);
+ }
+ </style>
+</head>
+<body>
+ <canvas id="canvas" width="200" height="200"></canvas>
+ <script>
+ let canvas = document.getElementById('canvas');
+ canvas.mozPrintCallback = (obj) => {
+ let ctx = obj.context;
+ // Intentionally use a different fallback font than the test file so that
+ // if the font fails to load the test and reference will still be
+ // different.
+ ctx.font = '10px test, sans-serif';
+ ctx.fillText("lmnop", 20, 20);
+ obj.done();
+ window.postMessage("ready", "*");
+ };
+ </script>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/printpreview_helper.xhtml b/layout/base/tests/chrome/printpreview_helper.xhtml
new file mode 100644
index 0000000000..e40d2e4d5b
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_helper.xhtml
@@ -0,0 +1,1721 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window onload="runTests()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <iframe style="min-height: 200px; min-width: 600px" type="content"></iframe>
+ <iframe style="min-height: 200px; min-width: 600px" type="content"></iframe>
+<script type="application/javascript">
+<![CDATA[
+// Note: We can't use window.frames directly here because the type="content"
+// attributes isolate the frames into their own BrowsingContext hierarchies.
+let frameElts = document.getElementsByTagName("iframe");
+
+var is = window.arguments[0].is;
+var isnot = window.arguments[0].isnot;
+var ok = window.arguments[0].ok;
+var todo = window.arguments[0].todo;
+var info = window.arguments[0].info;
+var SimpleTest = window.arguments[0].SimpleTest;
+var gWbp;
+var gPrintPreviewWindow;
+var gPrintPreviewBrowser;
+var ctx1;
+var ctx2;
+var counter = 0;
+
+var file = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties)
+ .get("TmpD", Ci.nsIFile);
+filePath = file.path;
+
+function printpreview(options = {}) {
+ let resolve;
+ let promise = new Promise(r => { resolve = r });
+ var listener = {
+ onLocationChange: function(webProgress, request, location, flags) { },
+ onProgressChange: function(webProgress, request, curSelfProgress,
+ maxSelfProgress, curTotalProgress,
+ maxTotalProgress) {
+ info("onProgressChange", [...arguments].join(", "));
+ },
+ onSecurityChange: function(webProgress, request, state) { },
+ onStateChange: function(webProgress, request, stateFlags, status) {
+ info("onStateChange", [...arguments].join(", "));
+ if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
+ setTimeout(resolve, 0);
+ }
+ },
+ onStatusChange: function(webProgress, request, status, message) {
+ info("onStatusChange", [...arguments].join(", "));
+ },
+ onContentBlockingEvent: function(webProgress, request, event) {
+ info("onContentBlockingEvent", [...arguments].join(", "));
+ },
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsIWebProgressListener) ||
+ iid.equals(Ci.nsISupportsWeakReference))
+ return this;
+ throw Components.Exception("", Cr.NS_NOINTERFACE);
+ }
+ }
+ var settings = Cc["@mozilla.org/gfx/printsettings-service;1"]
+ .getService(Ci.nsIPrintSettingsService).createNewPrintSettings();
+ settings.printBGColors = true;
+ settings.headerStrLeft = "";
+ settings.headerStrRight = "";
+ settings.footerStrLeft = "";
+ settings.footerStrRight = "";
+ settings.unwriteableMarginTop = 0;
+ settings.unwriteableMarginRight = 0;
+ settings.unwriteableMarginLeft = 0;
+ settings.unwriteableMarginBottom = 0;
+ if (options.settings) {
+ for (let key in options.settings) {
+ settings[key] = options.settings[key];
+ }
+ }
+ var before = 0;
+ var after = 0;
+ function beforeprint() { ++before; }
+ function afterprint() { ++after; }
+ frameElts[0].contentWindow.addEventListener("beforeprint", beforeprint, true);
+ frameElts[0].contentWindow.addEventListener("afterprint", afterprint, true);
+ {
+ let bc = frameElts[0].contentWindow.browsingContext;
+ let browser = document.createXULElement("browser");
+ browser.setAttribute("type", "content");
+ browser.style.minHeight = "800px";
+ browser.style.maxWidth = browser.style.minWidth = "800px";
+ browser.setAttribute("initialBrowsingContextGroupId", bc.group.id);
+ browser.setAttribute("nodefaultsrc", "true");
+ document.documentElement.appendChild(browser);
+ gPrintPreviewBrowser = browser;
+
+ // Force docViewer creation and layout.
+ browser.browsingContext.docShell.document;
+ browser.getBoundingClientRect();
+
+ gPrintPreviewWindow = frameElts[0].contentWindow.printPreview(settings, listener, browser.browsingContext.docShell);
+ }
+ gWbp = gPrintPreviewWindow.docShell.docViewer;
+ gWbp.QueryInterface(Ci.nsIWebBrowserPrint);
+ is(before, 1, "Should have called beforeprint listener!");
+ if (!options.hasMozPrintCallback) {
+ // If there's a mozPrintCallback the after print event won't fire until
+ // later.
+ is(after, 1, "Should have called afterprint listener!");
+ }
+ frameElts[0].contentWindow.removeEventListener("beforeprint", beforeprint, true);
+ frameElts[0].contentWindow.removeEventListener("afterprint", afterprint, true);
+ return promise;
+}
+
+function exitprintpreview() {
+ gPrintPreviewWindow.docShell.exitPrintPreview();
+ gPrintPreviewBrowser.remove();
+}
+
+function finish() {
+ SimpleTest.finish();
+ window.close();
+}
+
+async function runTests()
+{
+ // This ensures we actually test the lazy-load of images in printpreview_images.
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.image-lazy-loading.root-margin.top", 0],
+ ["dom.image-lazy-loading.root-margin.bottom", 0],
+ ["dom.image-lazy-loading.root-margin.left", 0],
+ ["dom.image-lazy-loading.root-margin.right", 0],
+ ],
+ });
+ startTest1();
+}
+
+function compareCanvases(options = {}) {
+ const canvas1 = document.getElementsByTagName("canvas")[0];
+ const canvas2 = document.getElementsByTagName("canvas")[1];
+ let maxDifference = {};
+ const differingPixels = window.windowUtils.compareCanvases(canvas1, canvas2, maxDifference);
+ if (differingPixels) {
+ todo(false, "different: " + differingPixels + ", maxDifference: " + maxDifference.value);
+ todo(false, "TEST CASE: " + canvas1.toDataURL());
+ todo(false, "REFERENCE: " + canvas2.toDataURL());
+ }
+
+ let maxAllowedDifferent = options.maxDifferent || 0;
+ let maxAllowedDifference = options.maxDifference || 0;
+ return differingPixels <= maxAllowedDifferent && maxDifference.value <= maxAllowedDifference;
+}
+
+function addHTMLContent(parent) {
+ var n = parent.ownerDocument.createElement("div");
+ parent.appendChild(n);
+ var s = "<iframe width='500' height='40' src='data:text/plain,ThisIsAnIframeCreatedDuringPrintPreview'></iframe>";
+ s += "<table>";
+ for (var i = 1; i < 501; ++i) {
+ s += "<tr><td>Cell A" + i + "</td><td>Cell B" + i + "</td><td>Cell C" + i + "</td></tr>";
+ }
+ s += "</table>";
+ n.innerHTML = s;
+}
+
+async function startTest1() {
+ ctx1 = document.getElementsByTagName("canvas")[0].getContext("2d");
+ ctx2 = document.getElementsByTagName("canvas")[1].getContext("2d");
+ frameElts[0].contentDocument.body.innerHTML = "<div> </div><div>" + counter + " timers</div><div> </div>";
+
+ // Note this timeout is needed so that we can check that timers run
+ // after print preview, but not during it.
+ frameElts[0].contentWindow.wrappedJSObject.counter = counter;
+ frameElts[0].contentWindow.counterTimeout = "document.body.firstChild.nextSibling.innerHTML = ++counter + ' timers';" +
+ "window.setTimeout(counterTimeout, 0);";
+ frameElts[0].contentWindow.setTimeout(frameElts[0].contentWindow.counterTimeout, 0);
+ frameElts[0].contentDocument.body.firstChild.innerHTML = "Print preview";
+
+ await printpreview();
+ drawPrintPreviewWindow(ctx1);
+ frameElts[0].contentDocument.body.firstChild.innerHTML = "Galley presentation";
+
+ // Add some elements.
+ addHTMLContent(frameElts[0].contentDocument.body.lastChild);
+ // Delete them.
+ frameElts[0].contentDocument.body.lastChild.innerHTML = "";
+ // And readd.
+ addHTMLContent(frameElts[0].contentDocument.body.lastChild);
+
+ setTimeout(finalizeTest1, 1000);
+}
+
+function finalizeTest1() {
+ drawPrintPreviewWindow(ctx2);
+ exitprintpreview();
+ ok(compareCanvases(), "Canvas should be the same!");
+ counter = frameElts[0].contentWindow.counter;
+ // This timeout is needed so that we can check that timers do run after
+ // print preview.
+ setTimeout(runTest2, 1000);
+}
+
+function runTest2() {
+ isnot(frameElts[0].contentDocument.body.firstChild.nextSibling.textContent, "0 timers", "Timers should have run!");
+ isnot(frameElts[0].contentWindow.counter, 0, "Timers should have run!");
+ counter = frameElts[0].contentWindow.counter;
+ frameElts[0].contentWindow.counterTimeout = "";
+ setTimeout(runTest3, 0);
+}
+
+var elementIndex = 0;
+var compareEmptyElement = true;
+var emptyFormElements =
+ ["<input type='text'>",
+ "<input type='password'>",
+ "<input type='file'>",
+ "<input type='button'>",
+ "<input type='submit'>",
+ "<input type='reset'>",
+ "<input type='checkbox'>",
+ "<input type='radio'>",
+ "<select></select>",
+ "<select size='5'></select>",
+ "<textarea></textarea>"];
+
+var formElements =
+ ["<input type='text' value='text'>",
+ "<input type='password' value='password'>",
+ "<input type='file' value='" + filePath + "'>",
+ "<input type='button' value='button'>",
+ "<input type='submit' value='submit button'>",
+ "<input type='reset' value='reset button'>",
+ "<input type='checkbox' checked>",
+ "<input type='radio' checked>",
+ "<select><option>option1</option></select>",
+ "<select size='5'><option>1</option><option>2</option><option>3</option></select>",
+ "<textarea value='textarea'>textarea</textarea>"];
+
+function runTest3() {
+ if (compareEmptyElement) {
+ var currentIndex = elementIndex;
+ ++elementIndex;
+ if (elementIndex >= emptyFormElements.length) {
+ elementIndex = 0;
+ compareEmptyElement = false;
+ }
+ compareFormElementPrint(emptyFormElements[currentIndex], emptyFormElements[currentIndex], true);
+ return;
+ } else if (elementIndex < emptyFormElements.length) {
+ var currentIndex = elementIndex;
+ ++elementIndex;
+ compareFormElementPrint(emptyFormElements[currentIndex], formElements[currentIndex], false);
+ return;
+ }
+
+ setTimeout(runTest4, 0)
+}
+
+async function compareFormElementPrint(el1, el2, equals) {
+ frameElts[0].contentDocument.body.innerHTML = el1;
+ frameElts[0].contentDocument.body.firstChild.value =
+ frameElts[0].contentDocument.body.firstChild.getAttribute('value');
+ await printpreview();
+ drawPrintPreviewWindow(ctx1);
+ exitprintpreview();
+ frameElts[0].contentDocument.body.innerHTML = el2;
+ frameElts[0].contentDocument.body.firstChild.value =
+ frameElts[0].contentDocument.body.firstChild.getAttribute('value');
+ await printpreview();
+ drawPrintPreviewWindow(ctx2);
+ exitprintpreview();
+ is(compareCanvases(), equals,
+ "Comparing print preview didn't succeed [" + el1 + " : " + el2 + "]");
+ setTimeout(runTest3, 100);
+}
+
+// This is a crash test for bug 539060.
+function runTest4() {
+ frameElts[0].contentDocument.body.innerHTML =
+ "<iframe style='display: none;' src='data:text/html,<iframe>'></iframe>";
+ setTimeout(runTest4end, 500);
+}
+
+async function runTest4end() {
+ await printpreview();
+ exitprintpreview();
+
+ runTest5();
+}
+
+// This is a crash test for bug 595337
+async function runTest5() {
+ frameElts[0].contentDocument.body.innerHTML =
+ '<iframe style="position: fixed; visibility: hidden; bottom: 10em;"></iframe>' +
+ '<input contenteditable="true" style="display: table; page-break-before: left; width: 10000px;">';
+ await printpreview();
+ exitprintpreview();
+
+ setTimeout(runTest6, 0);
+}
+
+// Crash test for bug 878037
+function runTest6() {
+ frameElts[0].contentDocument.body.innerHTML =
+ '<style> li { list-style-image: url("animated.gif"); } </style>' +
+ '<li>Firefox will crash if you try and print this page</li>';
+
+ setTimeout(runTest6end, 500);
+}
+
+async function runTest6end() {
+ await printpreview();
+ exitprintpreview();
+
+ requestAnimationFrame(function() { setTimeout(runTest7); } );
+}
+
+async function runTest7() {
+ var contentText = "<a href='#'>mozilla</a><input>test<select><option>option1</option></select>";
+ // Create normal content
+ frameElts[0].contentDocument.body.innerHTML =
+ "<div>" + contentText + "</div>";
+ frameElts[0].contentDocument.body.firstChild.value =
+ frameElts[0].contentDocument.body.firstChild.getAttribute('value');
+ await printpreview();
+ drawPrintPreviewWindow(ctx1);
+ exitprintpreview();
+
+ frameElts[0].contentDocument.body.innerHTML = "<div></div>";
+ var sr = frameElts[0].contentDocument.body.firstChild.attachShadow({mode: "open"});
+ sr.innerHTML = contentText;
+ await printpreview();
+ drawPrintPreviewWindow(ctx2);
+ exitprintpreview();
+ ok(compareCanvases(), "Printing light DOM and shadow DOM should create same output");
+
+ requestAnimationFrame(function() { setTimeout(runTest8); } );
+}
+
+async function runTest8() {
+ // Test that fonts loaded with CSS and JS are printed the same.
+ const iframeElement = document.getElementsByTagName("iframe")[0];
+
+ // First, snapshot the page with font defined in CSS.
+ await new Promise((resolve) => {
+ iframeElement.addEventListener("load", resolve, { capture: true, once: true });
+ iframeElement.setAttribute("src", "printpreview_font_api_ref.html");
+ });
+ await printpreview();
+ drawPrintPreviewWindow(ctx1);
+ exitprintpreview();
+
+ // Second, snapshot the page with font loaded in JS.
+ await new Promise((resolve) => {
+ iframeElement.addEventListener("message", resolve, { capture: true, once: true });
+ iframeElement.setAttribute("src", "printpreview_font_api.html");
+ });
+ await printpreview();
+ drawPrintPreviewWindow(ctx2);
+ exitprintpreview();
+ ok(compareCanvases(), "Printing pages with fonts loaded from CSS and JS should be the same.");
+
+ requestAnimationFrame(function() { setTimeout(runTest9); } );
+}
+
+// Test for bug 1487649
+async function runTest9() {
+ frameElts[0].contentDocument.body.innerHTML = `
+ <svg width="100" height="100">
+ <rect width='100' height='100' fill='lime'/>
+ </svg>
+ `;
+
+ await printpreview();
+ drawPrintPreviewWindow(ctx1);
+ exitprintpreview();
+
+ frameElts[0].contentDocument.body.innerHTML = `
+ <svg width="100" height="100">
+ <defs>
+ <g id="useme">
+ <rect width='100' height='100' fill='lime'/>
+ </g>
+ </defs>
+ <use />
+ </svg>
+ `;
+
+ // Set the attribute explicitly because this is a chrome document, and the
+ // href attribute would get sanitized.
+ frameElts[0].contentDocument.querySelector("use").setAttribute("href", "#useme");
+
+ // Ensure the <use> shadow tree is created so we test what we want to test.
+ frameElts[0].contentDocument.body.offsetTop;
+
+ await printpreview();
+ drawPrintPreviewWindow(ctx2);
+ exitprintpreview();
+ ok(compareCanvases(), "Printing <use> subtrees should create same output");
+
+ requestAnimationFrame(function() { setTimeout(runTest10); } );
+}
+
+function drawPrintPreviewWindow(ctx) {
+ let width = gPrintPreviewWindow.innerWidth;
+ let height = gPrintPreviewWindow.innerHeight;
+ ctx.canvas.width = width;
+ ctx.canvas.height = height;
+ ctx.drawWindow(gPrintPreviewWindow, 0, 0, width, height, "rgb(255, 255, 255)");
+}
+
+// Test for bug 1524640
+async function runTest10() {
+ // Test that fonts loaded during mozprint callback are loaded into the cloned
+ // document.
+ const iframeElement = document.getElementsByTagName("iframe")[0];
+
+ // First, snapshot the page with font defined in CSS.
+ await new Promise((resolve) => {
+ iframeElement.addEventListener("load", resolve, { capture: true, once: true });
+ iframeElement.setAttribute("src", "printpreview_font_mozprintcallback_ref.html");
+ });
+ let mozPrintCallbackDone = new Promise((resolve) => {
+ iframeElement.addEventListener("message", resolve, { capture: true, once: true });
+ });
+ await printpreview({ hasMozPrintCallback: true });
+ await mozPrintCallbackDone;
+ drawPrintPreviewWindow(ctx1);
+ exitprintpreview();
+
+ // Second, snapshot the page with font loaded in JS.
+ await new Promise((resolve) => {
+ iframeElement.addEventListener("load", resolve, { capture: true, once: true });
+ iframeElement.setAttribute("src", "printpreview_font_mozprintcallback.html");
+ });
+ mozPrintCallbackDone = new Promise((resolve) => {
+ iframeElement.addEventListener("message", resolve, { capture: true, once: true });
+ });
+ await printpreview({ hasMozPrintCallback: true });
+ // Wait for the mozprintcallback to finish.
+ await mozPrintCallbackDone;
+ drawPrintPreviewWindow(ctx2);
+
+ exitprintpreview();
+ ok(compareCanvases(), "Printing pages with fonts loaded from a mozPrintCallback should be the same.");
+
+ requestAnimationFrame(function() { setTimeout(runTest11); } );
+}
+
+async function compareFiles(src1, src2, options = {}) {
+ const BASE = "https://example.org/chrome/layout/base/tests/chrome/";
+
+ info(`Comparing ${src1} with ${src2}`);
+ const iframeElement = document.getElementsByTagName("iframe")[0];
+
+ let messagePromise = null;
+ if (options.waitForMessage) {
+ messagePromise = new Promise(resolve => {
+ iframeElement.addEventListener("message", resolve, { capture: true, once: true });
+ });
+ }
+
+ await new Promise((resolve) => {
+ iframeElement.addEventListener("load", resolve, { capture: true, once: true });
+ iframeElement.setAttribute("src", new URL(src1, BASE).href);
+ });
+ let mediaElements = iframeElement.contentDocument.querySelectorAll(
+ "audio, video"
+ );
+ for (let mediaElement of mediaElements) {
+ let { widget } = SpecialPowers.wrap(iframeElement.contentWindow)
+ .windowGlobalChild.getActor("UAWidgets")
+ .widgets.get(mediaElement);
+ await widget.impl.Utils.l10n.translateRoots();
+ }
+
+ if (messagePromise) {
+ info("awaiting for message to arrive");
+ await messagePromise;
+ }
+
+ await printpreview(options.test || options);
+ drawPrintPreviewWindow(ctx1);
+ exitprintpreview();
+
+ await new Promise((resolve) => {
+ iframeElement.addEventListener("load", resolve, { capture: true, once: true });
+ iframeElement.setAttribute("src", new URL(src2, BASE).href);
+ });
+ mediaElements = iframeElement.contentDocument.querySelectorAll(
+ "audio, video"
+ );
+ for (let mediaElement of mediaElements) {
+ let { widget } = SpecialPowers.wrap(iframeElement.contentWindow)
+ .windowGlobalChild.getActor("UAWidgets")
+ .widgets.get(mediaElement);
+ await widget.impl.Utils.l10n.translateRoots();
+ }
+
+ await printpreview(options.ref || options);
+ drawPrintPreviewWindow(ctx2);
+ exitprintpreview();
+
+ is(compareCanvases(options), !options.expectDifference, `Printing ${src1} and ${src2} should${options.expectDifference ? ' not' : ''} produce the same results`);
+}
+
+// bug 1567105
+async function runTest11() {
+ await compareFiles("printpreview_quirks.html", "printpreview_quirks_ref.html");
+ requestAnimationFrame(function() { setTimeout(runTest12); } );
+}
+
+// bug 1621415
+async function runTest12() {
+ await compareFiles("test_document_adopted_styles.html", "test_document_adopted_styles_ref.html");
+ requestAnimationFrame(function() { setTimeout(runTest13); } );
+}
+
+// bug 1621415
+async function runTest13() {
+ await compareFiles("test_shadow_root_adopted_styles.html", "test_shadow_root_adopted_styles_ref.html");
+ requestAnimationFrame(function() { setTimeout(runTest14); } );
+}
+
+// bug 1622322
+async function runTest14() {
+ await compareFiles("test_shared_adopted_styles.html", "test_shared_adopted_styles_ref.html");
+ requestAnimationFrame(function() { setTimeout(runTest15); } );
+}
+
+// Crash test for bug 1615261
+async function runTest15() {
+ frameElts[0].contentDocument.body.innerHTML =
+ '<style>div { width: 100px; height: 100px; background-image: url("animated.gif"); } </style>' +
+ '<div>Firefox will crash if you try and print this page</div>';
+
+ // XXX Is there a more reliable way to wait for the background-image to load?
+ await new Promise(resolve => setTimeout(resolve, 500));
+
+ await printpreview();
+ await exitprintpreview();
+
+ requestAnimationFrame(function() { setTimeout(runTest16); } );
+}
+
+// Various image tests.
+async function runTest16() {
+ // fuzzy: SVG image in the test pixel-snaps different than <div> in the ref.
+ // (And on WebRender, the pixel-snapping seems to shift some pixels over a
+ // bit such that they're fully white vs. fully blue; hence 255 as the allowed
+ // color-channel difference.)
+ // XXXdholbert We should revisit this and adjust these thresholds (hopefully
+ // lower) after bug 1602410 lands.
+ await compareFiles("printpreview_images.html", "printpreview_images_ref.html", { maxDifferent: 118, maxDifference: 255 });
+ requestAnimationFrame(function() { setTimeout(runTest17); } );
+}
+
+async function runTest17() {
+ // fuzzy: SVG image in the test pixel-snaps different than <div> in the ref.
+ // (And on WebRender, the pixel-snapping seems to shift some pixels over a
+ // bit such that they're fully white vs. fully blue; hence 255 as the allowed
+ // color-channel difference.)
+ // XXXdholbert We should revisit this and adjust these thresholds (hopefully
+ // lower) after bug 1602410 lands.
+ await compareFiles("printpreview_images_sw.html", "printpreview_images_sw_ref.html", { waitForMessage: true, maxDifferent: 118, maxDifference: 255 });
+ requestAnimationFrame(() => setTimeout(runTest18));
+}
+
+async function runTest18() {
+ await compareFiles("printpreview_quirks.html", "printpreview_quirks_ref.html", {
+ settings: {
+ marginTop: 22,
+ marginBottom: 22,
+ marginLeft: 22,
+ marginRight: 22,
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest19));
+}
+
+async function runTest19() {
+ await compareFiles("color_adjust.html", "color_adjust_ref.html", {
+ test: {
+ settings: {
+ printBGColors: false,
+ printBGImages: false,
+ },
+ },
+ ref: {
+ settings: {
+ printBGColors: true,
+ printBGImages: true,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest20));
+}
+
+async function runTest20() {
+ frameElts[0].contentDocument.body.innerHTML =
+ '<style>div { page-break-after: always; }</style>' +
+ '<div>1</div>' +
+ '<div>2</div>' +
+ '<div>3</div>';
+ await printpreview();
+
+ is(gWbp.printPreviewCurrentPageNumber, 1,
+ "The initial current page number should be 1");
+
+ // Scroll to the second page.
+ gWbp.printPreviewScrollToPage(Ci.nsIWebBrowserPrint.PRINTPREVIEW_GOTO_PAGENUM, 2);
+
+ is(gWbp.printPreviewCurrentPageNumber, 2,
+ "The current page number should be 2");
+
+ // Scroll to the last page.
+ gWbp.printPreviewScrollToPage(Ci.nsIWebBrowserPrint.PRINTPREVIEW_END, 0);
+
+ is(gWbp.printPreviewCurrentPageNumber, 3,
+ "The current page number should be 3");
+
+ exitprintpreview();
+
+ requestAnimationFrame(() => setTimeout(runTest21));
+}
+
+async function runTest21() {
+ await compareFiles("data:text/html,<audio controls>", "data:text/html,<audio controls >"); // Shouldn't crash.
+ requestAnimationFrame(() => setTimeout(runTest22));
+}
+
+async function runTest22() {
+ // Similar to above runtTest20 but more specific for the logic to choose
+ // the current page in the new print preview UI so this test works only
+ // in the new print preview.
+ frameElts[0].contentDocument.body.innerHTML =
+ '<style>div { page-break-after: always; max-height: 2in; }</style>' +
+ '<div>1</div>' +
+ '<div>2</div>' +
+ '<div>3</div>' +
+ '<div>4</div>' +
+ '<div>5</div>' +
+ '<div>6</div>' +
+ '<div>7</div>' +
+ '<div>8</div>' +
+ '<div>9</div>' +
+ '<div>10</div>';
+
+ await printpreview({ settings: { paperHeight: 3 } });
+
+ const initialCurrentPageNumber = gWbp.printPreviewCurrentPageNumber;
+
+ // NOTE: In the cases the page hight is less than the half height of the
+ // print preview scroll port height, the initial current page number will
+ // not be 1.
+ ok(initialCurrentPageNumber >= 1,
+ "The initial current page number should be equal to or greater than 1");
+
+ const totalPageNumber = gWbp.printPreviewNumPages;
+ for (let n = initialCurrentPageNumber;
+ n <= totalPageNumber - initialCurrentPageNumber;
+ n++) {
+ // Scroll to the given page number and check the current page number.
+ gWbp.printPreviewScrollToPage(
+ Ci.nsIWebBrowserPrint.PRINTPREVIEW_GOTO_PAGENUM, n);
+ is(gWbp.printPreviewCurrentPageNumber, n,
+ `The current page number should be ${n}`);
+ }
+
+ // Scroll to the end of the scroll region.
+ gWbp.printPreviewScrollToPage(Ci.nsIWebBrowserPrint.PRINTPREVIEW_END, 0);
+
+ // Same as the initial current page number case, the last page might not
+ // be the current page if the page height is less than the half of the scroll
+ // port.
+ is(gWbp.printPreviewCurrentPageNumber,
+ totalPageNumber + 1 - initialCurrentPageNumber,
+ `The current page number should be ${totalPageNumber + 1 - initialCurrentPageNumber}`);
+
+ exitprintpreview();
+
+ requestAnimationFrame(() => setTimeout(runTest23));
+}
+
+async function runTest23() {
+ await compareFiles("printpreview_prettyprint.xml", "printpreview_prettyprint_ref.xhtml");
+ requestAnimationFrame(() => setTimeout(runTest24));
+}
+async function runTest24() {
+ await compareFiles("printpreview_mask.html", "data:text/html,", {
+ settings: {
+ printBGColors: false,
+ printBGImages: false,
+ },
+ expectDifference: true,
+ });
+ requestAnimationFrame(() => setTimeout(runTest25));
+}
+
+async function runTest25() {
+ await compareFiles("printpreview_downloadable_font.html", "printpreview_downloadable_font_ref.html");
+ requestAnimationFrame(() => setTimeout(runTest26));
+}
+
+async function runTest26() {
+ await compareFiles("printpreview_downloadable_font_in_iframe.html", "printpreview_downloadable_font_in_iframe_ref.html");
+ requestAnimationFrame(() => setTimeout(runTest27));
+}
+
+async function runTest27() {
+ await compareFiles("data:text/html,<style>:root { background-color: red; background-image: linear-gradient(red, red) }</style>", "data:text/html,", {
+ settings: {
+ printBGColors: false,
+ printBGImages: false,
+ }
+ });
+ requestAnimationFrame(() => setTimeout(runTest28));
+}
+
+async function runTest28() {
+ await compareFiles("data:text/html,<style>@page { margin: 0 }</style>Foo", "data:text/html,Foo", {
+ settings: {
+ honorPageRuleMargins: false,
+ marginTop: 1,
+ }
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest29));
+}
+
+async function runTest29() {
+ await compareFiles("data:text/html,<style>@page { margin: 0 }</style>Foo", "data:text/html,Foo", {
+ settings: {
+ honorPageRuleMargins: true,
+ marginTop: 1,
+ },
+ expectDifference: true,
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest30));
+}
+
+// Helper function to test trivial/unsupported pages-per-sheet values which we
+// just treat as 1 page-per-sheet (as if the attribute were unset.)
+// NOTE: The second data-URI's explicit "<body>" tag is not meant to affect the
+// rendering -- it's just a hack to ensure that the URIs themselves are
+// different, so that compareFiles() sees the two URIs as different and gets
+// the "load" notification that it depends on after switching between them.
+// We also include numPages in the tested URL/content here, so that if we get
+// a test-failure, it's easy to figure out which call to this function had the
+// failure.
+async function checkTrivialPagesPerSheetValue(numPages) {
+ let stringToDisplay = "TrivialPagesPerSheetVal" + numPages;
+ await compareFiles("data:text/html," + stringToDisplay,
+ "data:text/html,<body>" + stringToDisplay, {
+ test: {
+ settings: {
+ numPagesPerSheet: numPages,
+ },
+ },
+ ref: { settings: {} },
+ });
+}
+
+async function runTest30() {
+ await checkTrivialPagesPerSheetValue(1);
+ await checkTrivialPagesPerSheetValue(0);
+ await checkTrivialPagesPerSheetValue(-5);
+ await checkTrivialPagesPerSheetValue(7);
+ await checkTrivialPagesPerSheetValue(500);
+
+ requestAnimationFrame(() => setTimeout(runTest31));
+}
+
+// Helper function to test supported pages-per-sheet values that actually do
+// tiling (i.e. values greater than 1). We render the testcase and reference
+// case with zero page-margins and zero unwritable margins. (This makes it
+// tractable to create a reference case without having to account for margins
+// that are outside of the content area.)
+async function checkSupportedPagesPerSheetValue(src1, src2, numPages, fuzz) {
+ await compareFiles(src1, src2, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ numPagesPerSheet: numPages,
+ },
+ },
+ ref: {
+ settings: {
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+}
+
+// Pages-per-sheet: test the supported values.
+// First we test the perfect-square values: 4, 9, 16.
+// Then we test the other values, 2 and 6. (They require some extra bespoke
+// configuration to mock up their page-rotation, so their runTest functions are
+// a bit more verbose.)
+async function runTest31() {
+ // XXXdholbert On windows, our zero-margin settings aren't reliably respected
+ // for some reason; see bug 1680838. For now, we just account for that with a
+ // hefty amount of fuzz, guarded behind a platform-specific check so that we
+ // can keep this strict on other platforms.
+ let fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 101278, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ await checkSupportedPagesPerSheetValue("printpreview_pps4.html",
+ "printpreview_pps4_ref.html", 4, fuzz);
+
+ requestAnimationFrame(() => setTimeout(runTest32));
+}
+async function runTest32() {
+ let fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 130170, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ await checkSupportedPagesPerSheetValue("printpreview_pps9.html",
+ "printpreview_pps9_ref.html", 9, fuzz);
+
+ requestAnimationFrame(() => setTimeout(runTest33));
+}
+async function runTest33() {
+ let fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 145706, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ await checkSupportedPagesPerSheetValue("printpreview_pps16.html",
+ "printpreview_pps16_ref.html", 16,
+ fuzz);
+
+ requestAnimationFrame(() => setTimeout(runTest34));
+}
+
+async function runTest34() {
+ let fuzz = navigator.platform.includes("Win") ? // Workaround for bug 1680838
+ { maxDifferent: 44256, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ let test = "printpreview_pps2.html";
+ let ref = "printpreview_pps2_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ numPagesPerSheet: 2,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ orientation: 1, /* Landscape mode */
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest35));
+}
+
+async function runTest35() {
+ let fuzz = navigator.platform.includes("Win") ? // Workaround for bug 1680838
+ { maxDifferent: 88751, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ let test = "printpreview_pps6.html";
+ let ref = "printpreview_pps6_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 6,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ numPagesPerSheet: 6,
+ orientation: 1, /* Landscape mode */
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 6,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest36));
+}
+
+// Testcases for pages-per-sheet with nonzero unwriteable margin values:
+// ---------------------------------------------------------------------
+
+// In this subtest, the vertical scale-factor is more-severe and hence ends up
+// "winning", and we have a bit of extra space in the horizontal axis which we
+// distribute equally on either side (see the _ref.html file used below for
+// more details).
+async function runTest36() {
+ let fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 139464, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ let test = "printpreview_pps_uw4.html";
+ let ref = "printpreview_pps_uw4_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 4,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0.6,
+ unwriteableMarginRight: 0.1,
+ unwriteableMarginBottom: 0.4,
+ unwriteableMarginLeft: 0.3,
+ numPagesPerSheet: 4,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 4,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest37));
+}
+
+// In this subtest, the horizontal scale-factor is more-severe and hence ends
+// up "winning", and we have a bit of extra space in the vertical axis which we
+// distribute equally on either side (see the _ref.html file used below for
+// more details).
+async function runTest37() {
+ let fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 152268, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ let test = "printpreview_pps_uw9.html";
+ let ref = "printpreview_pps_uw9_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0.2,
+ unwriteableMarginRight: 0.8,
+ unwriteableMarginBottom: 0.4,
+ unwriteableMarginLeft: 1.2,
+ numPagesPerSheet: 9,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 10,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest38));
+}
+
+async function runTest38() {
+ let fuzz = navigator.platform.includes("Win") ? // Workaround for bug 1680838
+ { maxDifferent: 117744, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ let test = "printpreview_pps_uw2.html";
+ let ref = "printpreview_pps_uw2_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0.8,
+ unwriteableMarginRight: 0.6,
+ unwriteableMarginBottom: 1.2,
+ unwriteableMarginLeft: 0.4,
+ numPagesPerSheet: 2,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ /* Note: These are the same values we used for 'test' above, except
+ that here we've rotated the margins counterclockwise through the
+ sides, to account for the fact that we're specifying these margins
+ for a landscape-orientation page here vs. portrait-mode above.*/
+ unwriteableMarginTop: 0.6,
+ unwriteableMarginRight: 1.2,
+ unwriteableMarginBottom: 0.4,
+ unwriteableMarginLeft: 0.8,
+ orientation: 1, /* Landscape mode */
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest39));
+}
+
+// In this subtest, the vertical unwriteable margins exactly consume the full
+// pageHeight, so we don't have any space available for printing and we just
+// print a blank sheet. (This is mostly a stress test to be sure we don't
+// crash, hang, divide-by-zero, etc. in this edge case.)
+async function runTest39() {
+ let fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 254, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ let test = "data:text/html,Unwriteable-Margins-Too-Tall-To-See-This";
+ let ref = "data:text/html,<!-- runTest39 -->";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 4,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginTop: 3,
+ unwriteableMarginBottom: 2,
+ numPagesPerSheet: 4,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 4,
+ paperHeight: 5,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest40));
+}
+
+// In this subtest, the horizontal unwriteable margins consume more than the
+// full pageWidth, so we don't have any space available for printing and we
+// just print a blank sheet. (This is mostly a stress test to be sure we don't
+// crash, hang, divide-by-zero, etc. in this edge case.)
+async function runTest40() {
+ let fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 172, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ let test = "data:text/html,Unwriteable-Margins-Too-Wide-To-See-This";
+ let ref = "data:text/html,<!-- runTest40 -->";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 4,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginRight: 3,
+ unwriteableMarginLeft: 4,
+ numPagesPerSheet: 9,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 4,
+ paperHeight: 5,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest41));
+}
+
+// Drawing headers/footers with very large unwriteable margins. The specific
+// bug occurs when combined unwriteable are larger than half of the page's
+// dimensions.
+async function runTest41() {
+ // This test compares a rendered page to the headers/footers that print code
+ // generates. On Windows, workaround bug 1680838. On OS X, the headers/
+ // footers are sometimes slightly offset. See bug 1714217.
+ // It's not too big a deal to have a higher fuzz factor, since when
+ // bug 1713404 occurs no headers/footers at all are rendered. These higher
+ // fuzz factors will still catch this worst case on OS X.
+ if (navigator.platform.includes("Win")) {
+ var fuzz = { maxDifferent: 133, maxDifference: 255 }; // Bug 1680838
+ }
+ else if (navigator.platform.includes("Mac")) {
+ var fuzz = { maxDifferent: 60, maxDifference: 200 }; // Bug 1714217
+ }
+ else {
+ var fuzz = { maxDifferent: 14, maxDifference: 16 };
+ }
+
+ let test = "data:text/html,<!-- runTest41 -->";
+ let ref = "printpreview_bug1713404_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 2,
+ unwriteableMarginRight: 2,
+ unwriteableMarginTop: 2,
+ unwriteableMarginBottom: 2,
+ headerStrLeft: "|",
+ headerStrRight: "||",
+ footerStrLeft: "|||",
+ footerStrRight: "||||",
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginBottom: 0,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest42));
+}
+
+// Test that @page{ size: ... } works correctly with a smaller specified
+// @page{ size: ... } than the paper we are printing to. The test and ref use
+// varying margin and size properties to place elements in the same location.
+// This depends on Firefox's current behavior of putting undersized pages into
+// the upper left corner, rather than scaling or centering the page.
+async function runTest42() {
+ if (navigator.platform.includes("Mac")) {
+ var fuzz = { maxDifferent: 15, maxDifference: 8 };
+ }
+ let test = "print_page_size1.html";
+ let ref = "print_page_size1_ref.html";
+ await compareFiles(test, ref, fuzz);
+
+ requestAnimationFrame(() => setTimeout(runTest43));
+}
+
+// Test that @page{ size: ... } works correctly with a larger specified
+// @page{ size: ... } than the paper we are printing to. This specifically
+// tests scaling when only one page edge is too large.
+// This depends on Firefox's current behavior of scaling down any oversized
+// pages to fit onto a single physical page, and putting this aligned to the
+// upper left corner rather than centering the page.
+async function runTest43() {
+ if (navigator.platform.includes("Mac")) {
+ var fuzz = { maxDifferent: 15, maxDifference: 8 };
+ }
+ let test = "print_page_size2.html";
+ let ref = "print_page_size2_ref.html";
+ await compareFiles(test, ref, fuzz);
+
+ requestAnimationFrame(() => setTimeout(runTest44));
+}
+
+// Test that @page{ size: ... } works correctly with a smaller specified
+// @page{ size: ... } than the paper we are printing to. The test case uses
+// only the size property and the ref case uses only absolute positioning.
+// This depends on Firefox's current behavior of putting undersized pages into
+// the upper left corner, rather than scaling or centering the page.
+async function runTest44() {
+ if (navigator.platform.includes("Mac")) {
+ var fuzz = { maxDifferent: 15, maxDifference: 8 };
+ }
+ let test = "print_page_size3.html";
+ let ref = "print_page_size3_ref.html";
+ await compareFiles(test, ref, fuzz);
+ requestAnimationFrame(() => setTimeout(runTest45));
+}
+
+// Test that @page{ size: ... } results in scaling down the contents to fit on
+// a smaller paper size.
+// This depends on Firefox's current behavior of scaling oversized pages down
+// to fit onto the paper size.
+async function runTest45() {
+ if (navigator.platform.includes("Mac")) {
+ var fuzz = { maxDifferent: 15, maxDifference: 8 };
+ }
+ let test = "print_page_size4.html";
+ let ref = "print_page_size4_ref.html";
+ await compareFiles(test, ref, fuzz);
+ requestAnimationFrame(() => setTimeout(runTest46));
+}
+
+// Test that small elements don't get clipped from the bottom of the page when
+// using a < 1.0 scaling factor.
+async function runTest46() {
+ var fuzz = { maxDifferent: 0, maxDifference: 0 };
+ let test = "bug1722890.html";
+ let ref = "bug1722890_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ scaling: 0.5,
+ shrinkToFit: false
+ }
+ },
+ ref: {
+ settings: {
+ scaling: 1.0,
+ shrinkToFit: false
+ }
+ }
+ });
+ requestAnimationFrame(() => setTimeout(runTest47));
+}
+
+// Test for header/footer text clipping when printing with scaling factor.
+async function runTest47() {
+ // This test compares a rendered page to the headers/footers that print code
+ // generates. On Windows, workaround bug 1680838. On OS X, the headers/
+ // footers are sometimes slightly offset. See bug 1714217.
+ // It's not too big a deal to have a higher fuzz factor, since when
+ // bug 1730091 occurs most of the headers/footers are not rendered at all,
+ // and these fuzz factors will still catch that.
+ if (navigator.platform.includes("Win")) {
+ var fuzz = { maxDifferent: 200, maxDifference: 255 }; // Bug 1680838
+ }
+ else if (navigator.platform.includes("Mac")) {
+ var fuzz = { maxDifferent: 180, maxDifference: 255 }; // Bug 1714217
+ }
+ else {
+ var fuzz = { maxDifferent: 6, maxDifference: 16 };
+ }
+
+ let test = "data:text/html,<!-- runTest47 -->";
+ let ref = "printpreview_bug1730091_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ scaling: 1.3,
+ shrinkToFit: false,
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginBottom: 0,
+ headerStrLeft: "||||",
+ headerStrRight: "||||",
+ footerStrLeft: "||||",
+ footerStrRight: "||||",
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginBottom: 0,
+ },
+ },
+ });
+ requestAnimationFrame(() => setTimeout(runTest48));
+}
+
+// Test that even when downscaling happens due to CSS page-size, the
+// unwriteable margins are in units applicable to the resulting page as it is
+// actually printed.
+// https://bugzilla.mozilla.org/1769161
+async function runTest48() {
+ if (navigator.platform.includes("Win")) {
+ var fuzz = { maxDifferent: 816, maxDifference: 255 }; // Bug 1680838
+ } else {
+ var fuzz = { maxDifferent: 16, maxDifference: 255 };
+ }
+ let test = "bug1769161_1.html";
+ let ref = "bug1769161_1_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ settings: {
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 1,
+ unwriteableMarginRight: 1,
+ unwriteableMarginTop: 1,
+ unwriteableMarginBottom: 1,
+ },
+ });
+ requestAnimationFrame(() => setTimeout(runTest49));
+}
+
+// Same as runTest48, but uses different scaling factors.
+async function runTest49() {
+ if (navigator.platform.includes("Win")) {
+ var fuzz = { maxDifferent: 6472, maxDifference: 255 }; // Bug 1680838
+ } else {
+ var fuzz = { maxDifferent: 24, maxDifference: 255 };
+ }
+ let test = "bug1769161_2.html";
+ let ref = "bug1769161_2_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ settings: {
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 1,
+ unwriteableMarginRight: 1,
+ unwriteableMarginTop: 1,
+ unwriteableMarginBottom: 1,
+ },
+ });
+ requestAnimationFrame(() => setTimeout(runTest50));
+}
+
+// Test that when downscaling happens due to CSS page-size, the unwriteable
+// margins are equivalent to the @page margins after those margins are scaled.
+// https://bugzilla.mozilla.org/1769161
+async function runTest50() {
+ if (navigator.platform.includes("Win")) {
+ var fuzz = { maxDifferent: 816, maxDifference: 255 }; // Bug 1680838
+ } else {
+ var fuzz = { maxDifferent: 16, maxDifference: 255 };
+ }
+ let test = "bug1769161_3.html";
+ let ref = "bug1769161_3_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 1,
+ unwriteableMarginRight: 1,
+ unwriteableMarginTop: 1,
+ unwriteableMarginBottom: 1,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginBottom: 0,
+ },
+ },
+ });
+ requestAnimationFrame(() => setTimeout(runTest51));
+}
+
+// Same as runTest50, but uses different scaling factors.
+async function runTest51() {
+ if (navigator.platform.includes("Win")) {
+ var fuzz = { maxDifferent: 11764, maxDifference: 255 }; // Bug 1680838
+ } else {
+ var fuzz = { maxDifferent: 24, maxDifference: 255 };
+ }
+ let test = "bug1769161_4.html";
+ let ref = "bug1769161_4_ref.html";
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 1,
+ unwriteableMarginRight: 1,
+ unwriteableMarginTop: 1,
+ unwriteableMarginBottom: 1,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 5,
+ paperHeight: 5,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ unwriteableMarginLeft: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginBottom: 0,
+ },
+ },
+ });
+ requestAnimationFrame(() => setTimeout(runTest52));
+}
+
+async function runTest52() {
+ // Unwriteable margins can be ignored by setting the appropriate flag.
+ // Slightly different to avoid hang.
+ await compareFiles("data:text/html,Foo", "data:text/html,<div>Foo", {
+ maxDifferent: 0,
+ maxDifference: 0,
+ test: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 1,
+ unwriteableMarginRight: 1,
+ unwriteableMarginBottom: 1,
+ unwriteableMarginLeft: 1,
+ ignoreUnwriteableMargins: true,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest53));
+}
+
+async function runTest53() {
+ // Ensure that even when unwriteable margins are set to be taken into
+ // account, page rule margins can override it.
+ await compareFiles(
+ "data:text/html,<style>@page { margin: 0 }</style>Foo",
+ "data:text/html,<div>Foo",
+ {
+ maxDifferent: 0,
+ maxDifference: 0,
+ test: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 1,
+ unwriteableMarginRight: 1,
+ unwriteableMarginBottom: 1,
+ unwriteableMarginLeft: 1,
+ ignoreUnwriteableMargins: false,
+ honorPageRuleMargins: true,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest54));
+}
+
+async function runTest54() {
+ // `ignoreUnwriteableMargins` lets author-specified margins ignore
+ // unwriteable margins as well. Without this flag, the unwriteable
+ // margin is ignored iff `Margins: Default` is set (i.e.
+ // `honorPageRuleMargins` set) and the author specified CSS page
+ // margin is zero.
+ // Note: At least currently, both `ignoreUnwriteableMargins`
+ // and `honorPageRuleMargins` cannot be set through the printing UI.
+ // TODO: If this behaviour is desired is up for debate.
+ await compareFiles(
+ "data:text/html,<style>@page { margin: 0.1in }</style>Foo",
+ "data:text/html,<div>Foo",
+ {
+ maxDifferent: 0,
+ maxDifference: 0,
+ test: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 1,
+ unwriteableMarginRight: 1,
+ unwriteableMarginBottom: 1,
+ unwriteableMarginLeft: 1,
+ ignoreUnwriteableMargins: true,
+ honorPageRuleMargins: true,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0.1,
+ marginRight: 0.1,
+ marginBottom: 0.1,
+ marginLeft: 0.1,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest55));
+}
+
+async function runTest55() {
+ let test = "printpreview_pps_uw2.html";
+ let ref = "printpreview_pps_uw2_no_margin_ref.html";
+ let fuzz = navigator.platform.includes("Win") ? // Workaround for bug 1680838
+ { maxDifferent: 12870, maxDifference: 255 } :
+ { maxDifferent: 0, maxDifference: 0 };
+
+ // Unwriteable margins are successfully ignored, if requested,
+ // for pages-per-sheet.
+ await compareFiles(test, ref, {
+ maxDifferent: fuzz.maxDifferent,
+ maxDifference: fuzz.maxDifference,
+ test: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0.8,
+ unwriteableMarginRight: 0.6,
+ unwriteableMarginBottom: 1.2,
+ unwriteableMarginLeft: 0.4,
+ numPagesPerSheet: 2,
+ ignoreUnwriteableMargins: true,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 8,
+ paperHeight: 10,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ orientation: 1, /* Landscape mode */
+ },
+ },
+ });
+
+ requestAnimationFrame(() => setTimeout(runTest56));
+}
+
+async function runTest56() {
+ await compareFiles("printpreview_image_select.html", "printpreview_image_select_ref.html");
+ requestAnimationFrame(() => setTimeout(runTest57));
+}
+
+// Tests that printing with mixed page sizes doesn't crash.
+// These tests can't actually compare any pages after the first, so this only
+// verifies that we don't crash reflowing.
+async function runTest57() {
+ let test = "printpreview_mixed_page_size_001.html";
+ // The params are just to give the file unique URLs.
+ await compareFiles(test + "?test", test + "?ref");
+ requestAnimationFrame(() => setTimeout(runTest58));
+}
+
+// As with runTest57, this is only testing for crashes.
+// This includes fixed-position content, as this is the only way to get content
+// within the same chain of continuations onto pages with different sizes.
+async function runTest58() {
+ let test = "printpreview_mixed_page_size_002.html";
+ // The params are just to give the file unique URLs.
+ await compareFiles(test + "?test", test + "?ref");
+ finish();
+}
+
+]]></script>
+<table style="border: 1px solid black;" xmlns="http://www.w3.org/1999/xhtml">
+<tr><th>Print preview canvas 1</th><th>Print preview canvas 2</th></tr>
+<tr>
+<td><canvas height="800" width="800"></canvas></td>
+<td><canvas height="800" width="800"></canvas></td>
+</tr></table>
+</window>
diff --git a/layout/base/tests/chrome/printpreview_image_select.html b/layout/base/tests/chrome/printpreview_image_select.html
new file mode 100644
index 0000000000..b61a40774d
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_image_select.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<body>
+ <picture>
+ <source width="200" srcset="red.png 1w, green.png 200w">
+ <img>
+ </picture>
+</body>
diff --git a/layout/base/tests/chrome/printpreview_image_select_ref.html b/layout/base/tests/chrome/printpreview_image_select_ref.html
new file mode 100644
index 0000000000..7189a57642
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_image_select_ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<body>
+ <div style="width: 200px; height: 200px; background-color: green;"></div>
+</body>
diff --git a/layout/base/tests/chrome/printpreview_images.html b/layout/base/tests/chrome/printpreview_images.html
new file mode 100644
index 0000000000..6919002354
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_images.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<style>
+ img, object, svg, input { display: block }
+ div {
+ content: url(blue-32x32.png);
+ width: 32px;
+ height: 32px;
+ }
+</style>
+<div></div>
+<picture>
+ <source srcset="blue-32x32.png">
+ <img width=32 height=32>
+</picture>
+<picture>
+ <source srcset="blue-32x32.png" media="print">
+ <source srcset="animated.gif" media="not print">
+ <img width=32 height=32>
+</picture>
+<img src="blue-32x32.png" width=32 height=32>
+<object data="blue-32x32.png" width=32 height=32></object>
+<svg width="32" height="32">
+ <image x=0 y=0 href="blue-32x32.png" width=32 height=32></image>
+</svg>
+<input type="image" src="blue-32x32.png" width=32 height=32>
diff --git a/layout/base/tests/chrome/printpreview_images_ref.html b/layout/base/tests/chrome/printpreview_images_ref.html
new file mode 100644
index 0000000000..65a0df066c
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_images_ref.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<style>
+ div {
+ width: 32px;
+ height: 32px;
+ background-color: blue;
+ }
+</style>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
diff --git a/layout/base/tests/chrome/printpreview_images_sw.html b/layout/base/tests/chrome/printpreview_images_sw.html
new file mode 100644
index 0000000000..78b8a0dd88
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_images_sw.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<style>
+ img, object, svg, input { display: block }
+ div {
+ content: url(nonexistent.png?1);
+ width: 32px;
+ height: 32px;
+ }
+</style>
+<script>
+const WORKER = "printpreview_images_sw.js";
+if (location.href.includes("registered")) {
+ console.log("REGISTERED");
+ onload = function() {
+ postMessage("ready", "*");
+ }
+ onbeforeunload = function() {
+ navigator.serviceWorker.getRegistrations().then(function(registrations) {
+ for(let registration of registrations) {
+ registration.unregister()
+ }
+ })
+ navigator.serviceWorker.unregister(WORKER);
+ }
+} else {
+ navigator.serviceWorker.oncontrollerchange = function() {
+ location.href = location.href + "?registered";
+ };
+ navigator.serviceWorker.register(WORKER);
+}
+</script>
+<div></div>
+<picture>
+ <source srcset="nonexistent.png?2">
+ <img width=32 height=32>
+</picture>
+<picture>
+ <source srcset="nonexistent.png?3" media="print">
+ <source srcset="animated.gif" media="not print">
+ <img width=32 height=32>
+</picture>
+<img src="nonexistent.png?4" width=32 height=32>
+<svg width="32" height="32">
+ <image x=0 y=0 href="nonexistent.png?7" width=32 height=32></image>
+</svg>
+<input type="image" src="nonexistent.png?6" width=32 height=32>
diff --git a/layout/base/tests/chrome/printpreview_images_sw.js b/layout/base/tests/chrome/printpreview_images_sw.js
new file mode 100644
index 0000000000..bb0ab60b1f
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_images_sw.js
@@ -0,0 +1,11 @@
+self.addEventListener("fetch", event => {
+ if (event.request.url.includes("nonexistent.png")) {
+ event.respondWith(
+ fetch(event.request.url.replace("nonexistent.png", "blue-32x32.png"))
+ );
+ }
+});
+
+self.addEventListener("activate", event => {
+ event.waitUntil(clients.claim());
+});
diff --git a/layout/base/tests/chrome/printpreview_images_sw_ref.html b/layout/base/tests/chrome/printpreview_images_sw_ref.html
new file mode 100644
index 0000000000..2efb9e9199
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_images_sw_ref.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<style>
+ div {
+ width: 32px;
+ height: 32px;
+ background-color: blue;
+ }
+</style>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
diff --git a/layout/base/tests/chrome/printpreview_mask.html b/layout/base/tests/chrome/printpreview_mask.html
new file mode 100644
index 0000000000..f1ea3af255
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_mask.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<style>
+div {
+ background: black;
+ color: white;
+ -webkit-mask-image: linear-gradient(180deg,#000 60%,transparent);
+ mask-image: linear-gradient(180deg,#000 60%,transparent);
+}
+</style>
+<div>
+ Here's some text<br>
+ Here's some text<br>
+ Here's some text<br>
+ Here's some text<br>
+ Here's some text<br>
+</div>
diff --git a/layout/base/tests/chrome/printpreview_mixed_page_size_001.html b/layout/base/tests/chrome/printpreview_mixed_page_size_001.html
new file mode 100644
index 0000000000..a611299527
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_mixed_page_size_001.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+@page a {
+ size: 10in 5in;
+}
+@page b {
+ size: 6in 9in;
+}
+</style>
+<div style="page: a">a</div>
+<div style="page: b">b</div>
diff --git a/layout/base/tests/chrome/printpreview_mixed_page_size_002.html b/layout/base/tests/chrome/printpreview_mixed_page_size_002.html
new file mode 100644
index 0000000000..f55efef3e6
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_mixed_page_size_002.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<style>
+@page a {
+ size: 10in 5in;
+}
+@page b {
+ size: 6in 9in;
+}
+</style>
+<div style="display: flex; position: fixed;">
+ <div>static 1</div>
+ <div>static 2</div>
+</div>
+<div style="page: a">block a</div>
+<div style="page: b">block b</div>
diff --git a/layout/base/tests/chrome/printpreview_pps16.html b/layout/base/tests/chrome/printpreview_pps16.html
new file mode 100644
index 0000000000..fc94819340
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps16.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!-- This is a testcase for a "16-pages-per-sheet" scenario.
+ There are 16 full-page color-swatches. -->
+<style>
+html, body { margin: 0; height: 100%; }
+.swatch {
+ box-sizing: border-box;
+ border: 120px solid;
+ height: 100%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: yellow; }
+.swatch:nth-child(3) { border-color: pink; }
+.swatch:nth-child(4) { border-color: orange; }
+.swatch:nth-child(5) { border-color: purple; }
+.swatch:nth-child(6) { border-color: olive; }
+.swatch:nth-child(7) { border-color: blue; }
+.swatch:nth-child(8) { border-color: tan; }
+.swatch:nth-child(9) { border-color: fuchsia; }
+.swatch:nth-child(10) { border-color: salmon; }
+.swatch:nth-child(11) { border-color: lightgreen; }
+.swatch:nth-child(12) { border-color: navy; }
+.swatch:nth-child(13) { border-color: brown; }
+.swatch:nth-child(14) { border-color: orchid; }
+.swatch:nth-child(15) { border-color: goldenrod; }
+.swatch:nth-child(16) { border-color: seagreen; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps16_ref.html b/layout/base/tests/chrome/printpreview_pps16_ref.html
new file mode 100644
index 0000000000..5807cc44ec
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps16_ref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!-- This is a reference case for a "16-pages-per-sheet" scenario. The width
+ and height of each "swatch" is 1/4 the width and height of the page. -->
+<style>
+html, body { margin: 0; height: 100%; }
+body {
+ display: flex;
+ flex-flow: row wrap;
+}
+.swatch {
+ box-sizing: border-box;
+ border: 30px solid;
+ /* The height will be automatically set to the flex container's row height,
+ via default 'align-self' behavior (which ends up as 'stretch') */
+ flex: 1 25%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: yellow; }
+.swatch:nth-child(3) { border-color: pink; }
+.swatch:nth-child(4) { border-color: orange; }
+.swatch:nth-child(5) { border-color: purple; }
+.swatch:nth-child(6) { border-color: olive; }
+.swatch:nth-child(7) { border-color: blue; }
+.swatch:nth-child(8) { border-color: tan; }
+.swatch:nth-child(9) { border-color: fuchsia; }
+.swatch:nth-child(10) { border-color: salmon; }
+.swatch:nth-child(11) { border-color: lightgreen; }
+.swatch:nth-child(12) { border-color: navy; }
+.swatch:nth-child(13) { border-color: brown; }
+.swatch:nth-child(14) { border-color: orchid; }
+.swatch:nth-child(15) { border-color: goldenrod; }
+.swatch:nth-child(16) { border-color: seagreen; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps2.html b/layout/base/tests/chrome/printpreview_pps2.html
new file mode 100644
index 0000000000..a7f9fddae3
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<!-- This is a testcase for a "2-pages-per-sheet" scenario.
+ There are 2 full-page "swatches" with large colorful borders. -->
+<style>
+html, body { margin: 0; height: 100%; }
+.swatch {
+ box-sizing: border-box;
+ border: 240px solid;
+ height: 100%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: pink; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps2_ref.html b/layout/base/tests/chrome/printpreview_pps2_ref.html
new file mode 100644
index 0000000000..b1e8033c87
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps2_ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!-- This is a reference case for a "2-pages-per-sheet" scenario. The width and
+ height of each "swatch" is 0.625 the width and height of the page. That
+ 0.625 scale-factor comes from the fact that, when rendering the testcase,
+ we'll need to scale the page-width (8in) down enough to fit side-by-side
+ into half of the page height (10in/2 = 5in), on a rotated sheet. So we've
+ got to scale 8in to fit into 5in, which is a scale factor of 0.625. -->
+<style>
+html { height: 100%; }
+body {
+ height: 100%;
+ margin: 0;
+ box-sizing: border-box;
+
+ /* The testcase (rendered at 2-pages-per-sheet) will have 1.75in of extra
+ space in the vertical axis, which will be distributed equally with 0.875in
+ on the top and the bottom of the page grid. We mock that up as padding
+ here: */
+ padding: 0.875in 0;
+
+ /* We lay out the body as a row-oriented flex container, with two
+ side-by-side children which correspond to the two pages per sheet: */
+ display: flex;
+}
+.swatch {
+ box-sizing: border-box;
+
+ /* This represents the 240px border in the testcase, scaled down 0.625x: */
+ border: 150px solid;
+
+ /* Share the width equally among the swatches. (The height will be
+ automatically set to the flex container's row height, via default
+ 'align-self' behavior.) */
+ flex: 1;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: pink; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps4.html b/layout/base/tests/chrome/printpreview_pps4.html
new file mode 100644
index 0000000000..6e3d030c6d
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<!-- This is a testcase for a "4-pages-per-sheet" scenario.
+ There are 4 full-page "swatches" with large colorful borders. -->
+<style>
+html, body { margin: 0; height: 100%; }
+.swatch {
+ box-sizing: border-box;
+ border: 120px solid;
+ height: 100%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: yellow; }
+.swatch:nth-child(3) { border-color: pink; }
+.swatch:nth-child(4) { border-color: orange; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps4_ref.html b/layout/base/tests/chrome/printpreview_pps4_ref.html
new file mode 100644
index 0000000000..4ffbec505f
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps4_ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- This is a reference case for a "4-pages-per-sheet" scenario. The width
+ and height of each "swatch" is 1/2 the width and height of the page. -->
+<style>
+html, body { margin: 0; height: 100%; }
+body {
+ display: flex;
+ flex-flow: row wrap;
+}
+.swatch {
+ box-sizing: border-box;
+ border: 60px solid;
+ /* The height will be automatically set to the flex container's row height,
+ via default 'align-self' behavior (which ends up as 'stretch') */
+ flex: 1 50%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: yellow; }
+.swatch:nth-child(3) { border-color: pink; }
+.swatch:nth-child(4) { border-color: orange; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps6.html b/layout/base/tests/chrome/printpreview_pps6.html
new file mode 100644
index 0000000000..68722afba9
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps6.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!-- This is a testcase for a "6-pages-per-sheet" scenario.
+ There are 12 full-page color-swatches, which should be layed out over 2
+ sheets.
+
+ This test is specifically given more pages than fit on a sheet so that
+ at least one of our tests checks the case where we have more than one
+ sheet. -->
+<style>
+html, body { margin: 0; height: 100%; }
+.swatch {
+ box-sizing: border-box;
+ border: 120px solid;
+ height: 100%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: yellow; }
+.swatch:nth-child(3) { border-color: pink; }
+.swatch:nth-child(4) { border-color: orange; }
+.swatch:nth-child(5) { border-color: purple; }
+.swatch:nth-child(6) { border-color: olive; }
+.swatch:nth-child(7) { border-color: blue; }
+.swatch:nth-child(8) { border-color: tan; }
+.swatch:nth-child(9) { border-color: fuchsia; }
+.swatch:nth-child(10) { border-color: salmon; }
+.swatch:nth-child(11) { border-color: lightgreen; }
+.swatch:nth-child(12) { border-color: navy; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps6_ref.html b/layout/base/tests/chrome/printpreview_pps6_ref.html
new file mode 100644
index 0000000000..3af174e0fa
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps6_ref.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<!-- This is a reference case for a "6-pages-per-sheet" scenario. This file is
+ a mockup of a sheet with 6 pages, followed by a sheet with another 6 pages,
+ with the pages all having a 0.4x scale factor applied. -->
+<style>
+html { height: 100%; }
+body {
+ height: 100%;
+ margin: 0;
+ box-sizing: border-box;
+}
+
+.sheet {
+ height: 100%;
+
+ /* We lay out the body as a column-oriented flex container (whose children,
+ in turn, are rows). */
+ display: flex;
+ flex-direction: column;
+}
+
+.row {
+ /* Give each row an equal share of the available height: */
+ flex: 1;
+
+ /* ...and render them as row-oriented (by default) flex containers: */
+ display: flex;
+}
+
+.swatch {
+ box-sizing: border-box;
+
+ /* This represents the 120px border in the testcase, scaled down 0.4x: */
+ border: 48px solid;
+
+ /* Share the width equally among the swatches. (The height will be
+ automatically set to the flex container's row height, via default
+ 'align-self' behavior.) */
+ flex: 1;
+
+ /* The testcase (rendered at 6-pages-per-sheet) will have 0.2in of extra
+ space in the horizontal axis, which will be distributed equally with
+ 0.05in to the left and right of each page in the grid. We mock that up as
+ margin here: */
+ margin: 0 0.05in;
+}
+
+.sheet:nth-child(1) > .row:nth-child(1) > .swatch:nth-child(1) { border-color: cyan; }
+.sheet:nth-child(1) > .row:nth-child(1) > .swatch:nth-child(2) { border-color: yellow; }
+.sheet:nth-child(1) > .row:nth-child(2) > .swatch:nth-child(1) { border-color: pink; }
+.sheet:nth-child(1) > .row:nth-child(2) > .swatch:nth-child(2) { border-color: orange; }
+.sheet:nth-child(1) > .row:nth-child(3) > .swatch:nth-child(1) { border-color: purple; }
+.sheet:nth-child(1) > .row:nth-child(3) > .swatch:nth-child(2) { border-color: olive; }
+
+.sheet:nth-child(2) { break-before: always; }
+.sheet:nth-child(2) > .row:nth-child(1) > .swatch:nth-child(1) { border-color: blue; }
+.sheet:nth-child(2) > .row:nth-child(1) > .swatch:nth-child(2) { border-color: tan; }
+.sheet:nth-child(2) > .row:nth-child(2) > .swatch:nth-child(1) { border-color: fuchsia; }
+.sheet:nth-child(2) > .row:nth-child(2) > .swatch:nth-child(2) { border-color: salmon; }
+.sheet:nth-child(2) > .row:nth-child(3) > .swatch:nth-child(1) { border-color: lightgreen; }
+.sheet:nth-child(2) > .row:nth-child(3) > .swatch:nth-child(2) { border-color: navy; }
+</style>
+<div class="sheet">
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
+</div>
+<div class="sheet">
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
+</div>
diff --git a/layout/base/tests/chrome/printpreview_pps9.html b/layout/base/tests/chrome/printpreview_pps9.html
new file mode 100644
index 0000000000..341e5fdf81
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps9.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!-- This is a testcase for a "9-pages-per-sheet" scenario.
+ There are 9 full-page color-swatches. -->
+<style>
+html, body { margin: 0; height: 100%; }
+.swatch {
+ box-sizing: border-box;
+ border: 120px solid;
+ height: 100%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: yellow; }
+.swatch:nth-child(3) { border-color: pink; }
+.swatch:nth-child(4) { border-color: orange; }
+.swatch:nth-child(5) { border-color: purple; }
+.swatch:nth-child(6) { border-color: olive; }
+.swatch:nth-child(7) { border-color: blue; }
+.swatch:nth-child(8) { border-color: tan; }
+.swatch:nth-child(9) { border-color: fuchsia; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps9_ref.html b/layout/base/tests/chrome/printpreview_pps9_ref.html
new file mode 100644
index 0000000000..ab90c837aa
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps9_ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!-- This is a reference case for a "9-pages-per-sheet" scenario. The width
+ and height of each "swatch" is 1/3 the width and height of the page. -->
+<style>
+html, body { margin: 0; height: 100%; }
+body {
+ display: flex;
+ flex-flow: row wrap;
+}
+.swatch {
+ box-sizing: border-box;
+ border: 40px solid;
+ /* The height will be automatically set to the flex container's row height,
+ via default 'align-self' behavior (which ends up as 'stretch') */
+ /* Note: it's OK that the flex-basis isn't exactly 1/3 here.
+ Flexbox layout will give each flex item 33% of the width,
+ and then divide up the remaining amount equally. This
+ results in exactly 3 items fitting per row and each one
+ getting 1/3 of a row, which is all we're going for. */
+ flex: 1 33%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: yellow; }
+.swatch:nth-child(3) { border-color: pink; }
+.swatch:nth-child(4) { border-color: orange; }
+.swatch:nth-child(5) { border-color: purple; }
+.swatch:nth-child(6) { border-color: olive; }
+.swatch:nth-child(7) { border-color: blue; }
+.swatch:nth-child(8) { border-color: tan; }
+.swatch:nth-child(9) { border-color: fuchsia; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps_uw2.html b/layout/base/tests/chrome/printpreview_pps_uw2.html
new file mode 100644
index 0000000000..34d3af49de
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps_uw2.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<!-- This is a testcase for a "2-pages-per-sheet" scenario with nonzero
+ unwriteable margins. There are 2 full-page "swatches" with large colorful
+ borders. -->
+<style>
+html, body { margin: 0; height: 100%; }
+.swatch {
+ box-sizing: border-box;
+ border: 240px solid;
+ height: 100%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: pink; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps_uw2_no_margin_ref.html b/layout/base/tests/chrome/printpreview_pps_uw2_no_margin_ref.html
new file mode 100644
index 0000000000..223aab8d55
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps_uw2_no_margin_ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!-- This is a reference case for a "2-pages-per-sheet" scenario zero
+ unwriteable margins. We're scaling down 8in width to fit 2 in 10in,
+ so the scale factor is (10 / 2) / 8 = 0.625x. -->
+<style>
+html { height: 100%; }
+body {
+ height: 100%;
+ margin: 0;
+ box-sizing: border-box;
+
+ /* The testcase (rendered at 2-pages-per-sheet) will have 8 - (10in * 0.625)
+ * = 1.75in of extra vertical space. */
+ padding: 0.875in 0;
+
+ /* We lay out the body as a row-oriented flex container, with two
+ side-by-side children which correspond to the two pages per sheet: */
+ display: flex;
+}
+.swatch {
+ box-sizing: border-box;
+
+ /* This represents the 240px border in the testcase, scaled down 0.5x: */
+ border: 150px solid;
+
+ /* Share the width equally among the swatches. (The height will be
+ automatically set to the flex container's row height, via default
+ 'align-self' behavior.) */
+ flex: 1;
+ margin: 0;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: pink; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps_uw2_ref.html b/layout/base/tests/chrome/printpreview_pps_uw2_ref.html
new file mode 100644
index 0000000000..d923901096
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps_uw2_ref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!-- This is a reference case for a "2-pages-per-sheet" scenario with nonzero
+ unwriteable margins. We expect the pages to have a 0.5x scale-down
+ factor. That 0.5 scale-factor comes from the fact that, when rendering the
+ testcase, we'll need to scale the page-width (8in) down enough to fit
+ side-by-side into half of the sheet's available width (with the sheet
+ having been rotated to landscape mode), with the sheet's unwritable margin
+ having already been subtracted out. The sheet's width (in landscape mode)
+ is 10in, and its unwriteable margin in that axis is 2in, so it's got 8in
+ of available width to hold two side-by-side pages, i.e. 4in per page.
+ Since the page width was 8in, that makes for a 0.5x scale. -->
+<style>
+html { height: 100%; }
+body {
+ height: 100%;
+ margin: 0;
+ box-sizing: border-box;
+
+ /* The testcase (rendered at 2-pages-per-sheet) will have 2in of extra space
+ in the vertical axis, which will be distributed equally with 1in on the
+ top and the bottom of the page grid (separately from the sheet's
+ unwriteable margin). We mock that up as padding here: */
+ padding: 1in 0;
+
+ /* We lay out the body as a row-oriented flex container, with two
+ side-by-side children which correspond to the two pages per sheet: */
+ display: flex;
+}
+.swatch {
+ box-sizing: border-box;
+
+ /* This represents the 240px border in the testcase, scaled down 0.5x: */
+ border: 120px solid;
+
+ /* Share the width equally among the swatches. (The height will be
+ automatically set to the flex container's row height, via default
+ 'align-self' behavior.) */
+ flex: 1;
+
+ /* This margin is meant to mock up the unwriteable margin for each page on
+ our sheet; it's exactly 0.5x the unwriteableMargin values specified for
+ the testcase in printpreview_helper.xhtml. */
+ margin: 0.4in 0.3in 0.6in 0.2in;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: pink; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps_uw4.html b/layout/base/tests/chrome/printpreview_pps_uw4.html
new file mode 100644
index 0000000000..6e3d030c6d
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps_uw4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<!-- This is a testcase for a "4-pages-per-sheet" scenario.
+ There are 4 full-page "swatches" with large colorful borders. -->
+<style>
+html, body { margin: 0; height: 100%; }
+.swatch {
+ box-sizing: border-box;
+ border: 120px solid;
+ height: 100%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: yellow; }
+.swatch:nth-child(3) { border-color: pink; }
+.swatch:nth-child(4) { border-color: orange; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps_uw4_ref.html b/layout/base/tests/chrome/printpreview_pps_uw4_ref.html
new file mode 100644
index 0000000000..a603ff2be9
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps_uw4_ref.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<!-- This is a reference case for a "4-pages-per-sheet" scenario. This file is
+ a mockup of a sheet with 4 pages, with the pages all having a 0.4x scale
+ scale factor applied. (We end up with that scale factor by subtracting the
+ requested unwriteable margins from the sheet, and dividing up the
+ remaining space equally among the "virtual pages".) -->
+<style>
+html {
+ display: flex;
+ height: 100%;
+ margin: 0;
+}
+body {
+ /* As a flex item (a child of the html element), fill the available area. */
+ flex: 1;
+
+ /* We lay out the body as a column-oriented flex container (whose children,
+ in turn, are rows). */
+ display: flex;
+ flex-direction: column;
+
+ /* These values come directly from the unwriteableMargin values in the
+ testcase's configuration code in printpreview_helper.xhtml. */
+ margin-top: 0.6in;
+ margin-right: 0.1in;
+ margin-bottom: 0.4in;
+ margin-left: 0.3in;
+}
+
+.row {
+ /* Give each row an equal share of the available height: */
+ flex: 1;
+
+ /* ...and render them as row-oriented (by default) flex containers: */
+ display: flex;
+}
+
+.swatch {
+ box-sizing: border-box;
+
+ /* These represent the 120px borders in the testcase, scaled down 0.4x: */
+ border: 48px solid;
+
+ /* Share the width equally among the swatches. (The height will be
+ automatically set to the flex container's row height, via default
+ 'align-self' behavior.) */
+ flex: 1;
+
+ /* These values come directly from the unwriteableMargin values in the
+ testcase's configuration code in printpreview_helper.xhtml, with
+ each measurement scaled down by exactly 0.4x. The extra 0.1in accounts
+ for the centering of each page in its grid cell. */
+ margin-top: 0.24in;
+ margin-right: calc(0.04in + 0.1in);
+ margin-bottom: 0.16in;
+ margin-left: calc(0.12in + 0.1in);
+}
+.row:nth-child(1) > .swatch:nth-child(1) { border-color: cyan; }
+.row:nth-child(1) > .swatch:nth-child(2) { border-color: yellow; }
+.row:nth-child(2) > .swatch:nth-child(1) { border-color: pink; }
+.row:nth-child(2) > .swatch:nth-child(2) { border-color: orange; }
+</style>
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
diff --git a/layout/base/tests/chrome/printpreview_pps_uw9.html b/layout/base/tests/chrome/printpreview_pps_uw9.html
new file mode 100644
index 0000000000..9bd0e1f5a4
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps_uw9.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!-- This is a testcase for a "9-pages-per-sheet" scenario.
+ There are 9 full-page "swatches" with large colorful borders. -->
+<style>
+html, body { margin: 0; height: 100%; }
+.swatch {
+ box-sizing: border-box;
+ border: 120px solid;
+ height: 100%;
+}
+.swatch:nth-child(1) { border-color: cyan; }
+.swatch:nth-child(2) { border-color: yellow; }
+.swatch:nth-child(3) { border-color: pink; }
+.swatch:nth-child(4) { border-color: orange; }
+.swatch:nth-child(5) { border-color: purple; }
+.swatch:nth-child(6) { border-color: olive; }
+.swatch:nth-child(7) { border-color: blue; }
+.swatch:nth-child(8) { border-color: tan; }
+.swatch:nth-child(9) { border-color: fuchsia; }
+</style>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
+<div class="swatch"></div>
diff --git a/layout/base/tests/chrome/printpreview_pps_uw9_ref.html b/layout/base/tests/chrome/printpreview_pps_uw9_ref.html
new file mode 100644
index 0000000000..de3cb1e08b
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_pps_uw9_ref.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!-- This is a reference case for a "9-pages-per-sheet" scenario. This file is
+ a mockup of a sheet with 9 pages, with the pages all having a 0.2x scale
+ scale factor applied. (We end up with that scale factor by subtracting the
+ requested unwriteable margins from the sheet, and dividing up the
+ remaining space equally among the "virtual pages".) -->
+<style>
+html {
+ display: flex;
+ height: 100%;
+ margin: 0;
+}
+body {
+ /* As a flex item (a child of the html element), fill the available area. */
+ flex: 1;
+
+ /* We lay out the body as a column-oriented flex container (whose children,
+ in turn, are rows). */
+ display: flex;
+ flex-direction: column;
+
+ /* These values come directly from the unwriteableMargin values in the
+ testcase's configuration code in printpreview_helper.xhtml. */
+ margin-top: 0.2in;
+ margin-right: 0.8in;
+ margin-bottom: 0.4in;
+ margin-left: 1.2in;
+}
+
+.row {
+ /* Give each row an equal share of the available height: */
+ flex: 1;
+
+ /* ...and render them as row-oriented (by default) flex containers: */
+ display: flex;
+}
+
+.swatch {
+ box-sizing: border-box;
+
+ /* These represent the 120px borders in the testcase, scaled down 0.2x: */
+ border: 24px solid;
+
+ /* Share the width equally among the swatches. (The height will be
+ automatically set to the flex container's row height, via default
+ 'align-self' behavior.) */
+ flex: 1;
+
+ /* These values come directly from the unwriteableMargin values in the
+ testcase's configuration code in printpreview_helper.xhtml, with
+ each measurement scaled down by exactly 0.2x. The extra 0.5667in accounts
+ for the centering of each page in its grid cell. */
+ margin-top: calc(0.04in + 0.5667in);
+ margin-right: 0.16in;
+ margin-bottom: calc(0.08in + 0.5667in);
+ margin-left: 0.24in;
+}
+.row:nth-child(1) > .swatch:nth-child(1) { border-color: cyan; }
+.row:nth-child(1) > .swatch:nth-child(2) { border-color: yellow; }
+.row:nth-child(1) > .swatch:nth-child(3) { border-color: pink; }
+.row:nth-child(2) > .swatch:nth-child(1) { border-color: orange; }
+.row:nth-child(2) > .swatch:nth-child(2) { border-color: purple; }
+.row:nth-child(2) > .swatch:nth-child(3) { border-color: olive; }
+.row:nth-child(3) > .swatch:nth-child(1) { border-color: blue; }
+.row:nth-child(3) > .swatch:nth-child(2) { border-color: tan; }
+.row:nth-child(3) > .swatch:nth-child(3) { border-color: fuchsia; }
+</style>
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
+<div class="row">
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+ <div class="swatch"></div>
+</div>
diff --git a/layout/base/tests/chrome/printpreview_prettyprint.xml b/layout/base/tests/chrome/printpreview_prettyprint.xml
new file mode 100644
index 0000000000..759d5066cf
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_prettyprint.xml
@@ -0,0 +1 @@
+<out>Here be sea hags</out>
diff --git a/layout/base/tests/chrome/printpreview_prettyprint_ref.xhtml b/layout/base/tests/chrome/printpreview_prettyprint_ref.xhtml
new file mode 100644
index 0000000000..7309425fb4
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_prettyprint_ref.xhtml
@@ -0,0 +1,3 @@
+<out><div id="top" xmlns="http://www.w3.org/1999/xhtml"><link href="chrome://global/content/xml/XMLPrettyPrint.css" type="text/css" rel="stylesheet"/><div id="header"><p>
+ This XML file does not appear to have any style information associated with it. The document tree is shown below.
+ </p></div><main id="tree" class="highlight"><div>&lt;<span class="start-tag">out</span>&gt;<span class="text">Here be sea hags</span>&lt;/<span class="end-tag">out</span>&gt;</div></main></div></out>
diff --git a/layout/base/tests/chrome/printpreview_quirks.html b/layout/base/tests/chrome/printpreview_quirks.html
new file mode 100644
index 0000000000..fa8714a0f7
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_quirks.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+ .HiDdEn { display: none }
+</style>
+<body class="hidden">
+ Some content that I should be able to print.
+</body>
diff --git a/layout/base/tests/chrome/printpreview_quirks_ref.html b/layout/base/tests/chrome/printpreview_quirks_ref.html
new file mode 100644
index 0000000000..4c6fcce1f6
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_quirks_ref.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<meta charset="utf-8">
+<body>
+ Some content that I should be able to print.
+</body>
diff --git a/layout/base/tests/chrome/red.png b/layout/base/tests/chrome/red.png
new file mode 100644
index 0000000000..57bf3ddc52
--- /dev/null
+++ b/layout/base/tests/chrome/red.png
Binary files differ
diff --git a/layout/base/tests/chrome/test_bug1018265.xhtml b/layout/base/tests/chrome/test_bug1018265.xhtml
new file mode 100644
index 0000000000..8e8ac9a119
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug1018265.xhtml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1018265
+-->
+<window title="Mozilla Bug 1018265"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="run()">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 1018265 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ function run() {
+ window.openDialog("file_bug1018265.xhtml", "documentViewerTest", "chrome,width=100,height=100,noopener", window);
+ }
+
+ function done() {
+ ok(true, "done");
+ setTimeout(function() { SimpleTest.finish(); }, 0);
+ }
+ ]]>
+ </script>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1018265"
+ target="_blank">Mozilla Bug 1018265</a>
+ </body>
+</window>
diff --git a/layout/base/tests/chrome/test_bug1041200.xhtml b/layout/base/tests/chrome/test_bug1041200.xhtml
new file mode 100644
index 0000000000..365ecf2825
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug1041200.xhtml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ SimpleTest.waitForExplicitFinish();
+ // Run the test in a separate window so that the test runs as a chrome
+ // window
+ window.openDialog("bug1041200_window.html", "bug1041200",
+ "chrome,width=800,height=800,noopener", window);
+ ]]>
+ </script>
+</window>
diff --git a/layout/base/tests/chrome/test_bug396367-1.html b/layout/base/tests/chrome/test_bug396367-1.html
new file mode 100644
index 0000000000..63b33d335d
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug396367-1.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=396367
+-->
+<head>
+ <title>Test for Bug 396367</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ function finish() {
+ ok(true, "didn't crash");
+ top.docShell.browsingContext.textZoom = 1;
+ SimpleTest.finish();
+ }
+ </script>
+</head>
+<body>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=396367">Mozilla Bug 396367</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+
+<input>
+<script>document.body.setAttribute('style', 'display: -moz-box; overflow: scroll;');</script>
+<script>
+top.docShell.browsingContext.textZoom = Math.floor(10 * Math.random()) / 4 + 0.2;
+document.documentElement.offsetHeight;
+setTimeout(finish, 0);
+</script>
+
+
+</pre>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_bug396367-2.html b/layout/base/tests/chrome/test_bug396367-2.html
new file mode 100644
index 0000000000..2a751cd8be
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug396367-2.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=396367
+-->
+<head>
+ <title>Test for Bug 396367</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <style>select::after { content:"m"; }</style>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ function finish() {
+ ok(true, "didn't crash");
+ top.docShell.browsingContext.textZoom = 1;
+ SimpleTest.finish();
+ }
+ </script>
+</head>
+<body>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=396367">Mozilla Bug 396367</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+
+<div style="overflow: scroll; float: left;">
+
+<select></select>
+
+<li style="display: table-cell;">
+
+<script>
+top.docShell.browsingContext.textZoom = Math.floor(10 * Math.random()) / 4 + 0.2;
+document.documentElement.offsetHeight;
+setTimeout(finish, 0);
+</script>
+</li>
+</div>
+
+
+</pre>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_bug420499.xhtml b/layout/base/tests/chrome/test_bug420499.xhtml
new file mode 100644
index 0000000000..22fefd7987
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug420499.xhtml
@@ -0,0 +1,126 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=420499
+-->
+<window title="Mozilla Bug 420499" onload="setTimeout(focusInput, 500);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+
+
+ <menu id="menu" label="Menu">
+ <menupopup id="file-popup">
+ <!-- <input xmlns="http://www.w3.org/1999/xhtml" id="some-text" maxlength="10" value="some text"/> -->
+ <menu label="submenu">
+ <menupopup id="file-popup-inner">
+
+ <menuitem label="Item1"/>
+ <menuitem label="Item2"/>
+ <input xmlns="http://www.w3.org/1999/xhtml" id="some-text" maxlength="10" value="some more text"/>
+ </menupopup>
+ </menu>
+ <menuitem label="Item3"/>
+ <menuitem label="Item4"/>
+ </menupopup>
+ </menu>
+
+ <popupset>
+ <menupopup id="contextmenu">
+ <menuitem label="Cut"/>
+ <menuitem label="Copy"/>
+ <menuitem label="Paste"/>
+ </menupopup>
+ <tooltip id="tooltip" orient="vertical">
+ <description value="This is a tooltip"/>
+ </tooltip>
+ </popupset>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" bgcolor="white">
+
+ <p id="par1">Paragraph 1</p>
+ <p id="par2">Paragraph 2</p>
+ <p id="par3">Paragraph 3</p>
+ <p id="par4">Paragraph 4</p>
+ <p id="par5">Paragraph 5</p>
+
+ <input type="text" id="text-input" maxlength="10" value="some more text"/> <br />
+
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=420499"
+ target="_blank">Mozilla Bug 420499</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ /** Test for Bug 420499 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function getSelectionController() {
+ return window.docShell
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+ }
+
+ function isCaretVisible() {
+ var docShell = window.docShell;
+ var selCon = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+ return selCon.caretVisible;
+ }
+
+ function focusInput() {
+ ok(!isCaretVisible(), "Caret shouldn't be visible");
+ $("text-input").focus();
+ ok(isCaretVisible(), "Caret should be visible when input focused");
+ window.addEventListener("popupshown", popupMenuShownHandler);
+ $("menu").open = true;
+ }
+
+ function popupMenuShownHandler() {
+ window.removeEventListener("popupshown", popupMenuShownHandler);
+ ok(!isCaretVisible(), "Caret shouldn't be visible when menu open");
+ window.addEventListener("popuphidden", ensureParagraphFocused);
+ $("menu").open = false;
+ }
+
+ function ensureParagraphFocused() {
+ window.removeEventListener("popuphidden", ensureParagraphFocused);
+ ok(isCaretVisible(), "Caret should have returned to previous focus");
+ window.addEventListener("popupshown", popupMenuShownHandler2);
+ $("contextmenu").openPopup($('text-input'), "topleft" , -1 , -1 , true, true);
+ }
+
+ function popupMenuShownHandler2() {
+ window.removeEventListener("popupshown", popupMenuShownHandler2);
+ ok(isCaretVisible(), "Caret should be visible when context menu open");
+ window.addEventListener("popuphidden", ensureParagraphFocused2);
+ document.getElementById("contextmenu").hidePopup();
+ }
+
+ function ensureParagraphFocused2() {
+ window.removeEventListener("popuphidden", ensureParagraphFocused2);
+ ok(isCaretVisible(), "Caret should still be visible");
+ window.addEventListener("popupshown", tooltipShownHandler);
+ $("tooltip").openPopup($('text-input'), "topleft" , -1 , -1 , false, true);
+ }
+
+ function tooltipShownHandler() {
+ window.removeEventListener("popupshown", tooltipShownHandler);
+ ok(isCaretVisible(), "Caret should be visible when tooltip is visible");
+ window.addEventListener("popuphidden", ensureParagraphFocused3);
+ document.getElementById("tooltip").hidePopup();
+ }
+
+ function ensureParagraphFocused3() {
+ window.removeEventListener("popuphidden", ensureParagraphFocused2);
+ ok(isCaretVisible(), "Caret should still be visible");
+ SimpleTest.finish();
+ }
+ ]]></script>
+</window>
diff --git a/layout/base/tests/chrome/test_bug458898.html b/layout/base/tests/chrome/test_bug458898.html
new file mode 100644
index 0000000000..a7913f9a2a
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug458898.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=458898
+-->
+<head>
+ <title>Test for Bug 458898</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=458898">Mozilla Bug 458898</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+var win = window.browsingContext.topChromeWindow.openDialog("file_bug458898.html");
+
+function loaded() {
+ var disableWindowResizePref = "dom.disable_window_move_resize";
+ SpecialPowers.pushPrefEnv({"set":[[disableWindowResizePref, false]]}, function() {
+ win.sizeToContent();
+ ok(win.innerWidth >= 100, "innerWidth: " + win.innerWidth + " >= 100 ?");
+ ok(win.innerHeight >= 200, "innerHeight: " + win.innerHeight + " >= 200 ?");
+ win.close();
+ SimpleTest.finish();
+ });
+}
+
+win.addEventListener("load", loaded);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_bug465448.xhtml b/layout/base/tests/chrome/test_bug465448.xhtml
new file mode 100644
index 0000000000..fa9d1589a2
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug465448.xhtml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Bug 465448"
+ onload="loaded()"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+<script><![CDATA[
+SimpleTest.waitForExplicitFinish();
+var loadedCalled = false;
+var win = window.open("file_bug465448.html", "_blank", "width=600,height=600");
+
+function loaded() {
+ if (!loadedCalled) {
+ loadedCalled = true;
+ return;
+ }
+ win.sizeToContent();
+ win.sizeToContent();
+ win.sizeToContent();
+ win.sizeToContent();
+ win.sizeToContent();
+ win.sizeToContent();
+ ok(win.innerWidth >= 100, "innerWidth");
+ ok(win.innerHeight >= 200, "innerHeight");
+ win.close();
+ SimpleTest.finish();
+}
+]]></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/layout/base/tests/chrome/test_bug514660.xhtml b/layout/base/tests/chrome/test_bug514660.xhtml
new file mode 100644
index 0000000000..367eec8bf4
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug514660.xhtml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=514660
+-->
+<window title="Mozilla Bug 504311"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="doTest()">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=514660"
+ target="_blank">Mozilla Bug 514660</a>
+<textarea></textarea>
+</body>
+ <!-- test code goes here -->
+<script type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+function doTest()
+{
+ var viewer = window.docShell.docViewer;
+ viewer.authorStyleDisabled = true;
+
+ document.documentElement.getBoundingClientRect();
+ ok(true, "Didn't crash");
+
+ viewer.authorStyleDisabled = false;
+
+ SimpleTest.finish();
+}
+]]></script>
+</window>
diff --git a/layout/base/tests/chrome/test_bug533845.xhtml b/layout/base/tests/chrome/test_bug533845.xhtml
new file mode 100644
index 0000000000..3ea21cb9b7
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug533845.xhtml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=533845
+-->
+<window title="Mozilla Bug 533845"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="doTest()">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<panel id="panel" style="width: 500px; height: 500px">
+ <iframe type="content" id="contentFrame" src="data:text/html,&lt;html&gt;&lt;body onclick='document.body.textContent=1'&gt;This is a panel!&lt;/body&gt;&lt;/html&gt;" width="500" height="500"/>
+</panel>
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=533845"
+ target="_blank">Mozilla Bug 533845</a>
+</body>
+ <!-- test code goes here -->
+<script type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+function doTest() {
+ let panel = document.getElementById("panel");
+ panel.addEventListener("popupshown", function onpopupshown() {
+ continueTest();
+ panel.addEventListener("popuphidden", function onpopuphidden() {
+ SimpleTest.finish();
+ }, { once: true });
+ panel.hidePopup();
+ }, { once: true });
+ panel.openPopup();
+}
+
+function continueTest() {
+ var ifrwindow = document.getElementById("contentFrame").contentWindow;
+ ifrwindow.focus();
+ var utils = ifrwindow.windowUtils;
+ var rect = ifrwindow.document.body.getBoundingClientRect();
+ var x = rect.left + (rect.width/2);
+ var y = rect.top + (rect.height/2);
+ utils.sendMouseEvent("mousedown", x, y, 0, 1, 0);
+ utils.sendMouseEvent("mouseup", x, y, 0, 1, 0);
+ is(ifrwindow.document.body.textContent, "1", "Should have got a click event!");
+}
+
+]]></script>
+</window>
diff --git a/layout/base/tests/chrome/test_bug551434.html b/layout/base/tests/chrome/test_bug551434.html
new file mode 100644
index 0000000000..5e21cf6408
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug551434.html
@@ -0,0 +1,95 @@
+<html>
+<head>
+ <title>Test for Bug 551434</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+</div>
+<pre id="test">
+<input id="i1" onkeydown="gKeyDown1++; $('i2').focus();" onkeypress="gKeyPress1++;" onkeyup="gKeyUp1++;"/>
+<input id="i2" onkeydown="gKeyDown2++;" onkeypress="gKeyPress2++;" onkeyup="gKeyUp2++;"/>
+
+<input id="i3" onkeydown="gKeyDown3++; frames[0].document.getElementById('i4').focus();"
+ onkeypress="gKeyPress3++;" onkeyup="gKeyUp3++;"/>
+<iframe id="iframe" src="http://example.org/chrome/layout/base/tests/chrome/bug551434_childframe.html"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var gKeyDown1 = 0, gKeyPress1 = 0, gKeyUp1 = 0;
+var gKeyDown2 = 0, gKeyPress2 = 0, gKeyUp2 = 0;
+var gKeyDown3 = 0, gKeyPress3 = 0, gKeyUp3 = 0;
+
+function runTest()
+{
+ $("i1").focus();
+
+ // key events should not be retargeted when the focus changes to an
+ // element in the same document.
+ synthesizeKey("a", {type: "keydown"});
+ is(document.activeElement, $("i2"), "input 2 in focused");
+
+ synthesizeKey("a", {type: "keyup"});
+
+ is(gKeyDown1, 1, "keydown on input 1");
+ is(gKeyPress1, 0, "keypress on input 1");
+ is(gKeyUp1, 0, "keyup on input 1");
+ is(gKeyDown2, 0, "keydown on input 2");
+ is(gKeyPress2, 1, "keypress on input 2");
+ is(gKeyUp2, 1, "keyup on input 2");
+
+ is($("i1").value, "", "input 1 value");
+ is($("i2").value, "a", "input 2 value");
+
+ // key events should however be retargeted when the focus changes to an
+ // element in the a content document from a chrome document.
+ $("i3").focus();
+
+ var childWinObj = frames[0].wrappedJSObject;
+
+ sendString("b");
+ is(gKeyDown3, 1, "keydown on input 3");
+ is(gKeyPress3, 1, "keypress on input 3");
+ is(gKeyUp3, 1, "keyup on input 3");
+ is(childWinObj.gKeyDownChild, 0, "keydown on input 4");
+ is(childWinObj.gKeyPressChild, 0, "keypress on input 4");
+ is(childWinObj.gKeyUpChild, 0, "keyup on input 4");
+
+ var i4 = frames[0].document.getElementById("i4");
+ is($("i3").value, "b", "input 3 value");
+ is(i4.value, "", "input 4 value");
+
+ is(document.activeElement, $("iframe"), "parent focus");
+ is(frames[0].document.activeElement, i4, "child focus");
+
+ // key events should also be retargeted when the focus changes to an
+ // element in a chrome document from a content document.
+ i4.addEventListener("keydown", () => $("i3").focus());
+
+ sendString("c");
+
+ is(gKeyDown3, 1, "keydown on input 3");
+ is(gKeyPress3, 1, "keypress on input 3");
+ is(gKeyUp3, 1, "keyup on input 3");
+ is(childWinObj.gKeyDownChild, 1, "keydown on input 4");
+ is(childWinObj.gKeyPressChild, 1, "keypress on input 4");
+ is(childWinObj.gKeyUpChild, 1, "keyup on input 4");
+
+ is($("i3").value, "b", "input 3 value");
+ is(i4.value, "c", "input 4 value");
+
+ is(document.activeElement, $("i3"), "parent focus");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(runTest);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/layout/base/tests/chrome/test_bug708062.html b/layout/base/tests/chrome/test_bug708062.html
new file mode 100644
index 0000000000..ee7df7d37d
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug708062.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=708062
+-->
+<head>
+ <title>Test for Bug 708062</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body onload="doTest()">
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=708062">Mozilla Bug 708062</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<iframe id="f" style="width:100px;"
+ src="data:text/html,A<div id='d' style='position:fixed;width:170px;top:0;right:0;height:1px;background:yellow;'>"></iframe>
+<pre id="test">
+
+<script>
+function isBoundingClientRect(e, r, msg) {
+ var BCR = e.getBoundingClientRect();
+ is([BCR.left, BCR.top, BCR.right, BCR.bottom].join(','), r, msg);
+}
+
+function doTest() {
+ var f = document.getElementById('f');
+
+ var d = f.contentDocument.getElementById('d');
+
+ isBoundingClientRect(d, "-70,0,100,1", "initial rect");
+ SpecialPowers.setFullZoom(f.contentWindow, 2);
+ isBoundingClientRect(d, "-120,0,50,1", "after zooming in");
+ SpecialPowers.setFullZoom(f.contentWindow, 1);
+ isBoundingClientRect(d, "-70,0,100,1", "after zooming back out");
+ SimpleTest.finish();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_bug812817.xhtml b/layout/base/tests/chrome/test_bug812817.xhtml
new file mode 100644
index 0000000000..c5eb747ea6
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug812817.xhtml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=812817
+-->
+<window title="Mozilla Bug 812817"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="doTest()">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<panel id="panel" width="200" height="200" onpopupshown="continueTest()">
+</panel>
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=812817"
+ target="_blank">Mozilla Bug 812817</a>
+</body>
+ <!-- test code goes here -->
+<script type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+var panel = document.getElementById('panel');
+function doTest() {
+ panel.openPopup(null, '', 500, 500, false, false, null);
+}
+
+function continueTest() {
+ panel.style.background = "url(blue-32x32.png)";
+ setTimeout(function() {
+ ok(true, "Didn't crash");
+ SimpleTest.finish();
+ }, 50);
+}
+
+]]></script>
+</window>
diff --git a/layout/base/tests/chrome/test_chrome_content_integration.xhtml b/layout/base/tests/chrome/test_chrome_content_integration.xhtml
new file mode 100644
index 0000000000..6e6be4761a
--- /dev/null
+++ b/layout/base/tests/chrome/test_chrome_content_integration.xhtml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/chrome-harness.js"></script>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ SimpleTest.waitForExplicitFinish();
+ // Run the test in a separate window so that the test runs as a chrome
+ // window
+ var root = getRootDirectory(window.location.href);
+ window.openDialog(root + "chrome_content_integration_window.xhtml", "chrome_content_integration",
+ "chrome,width=200,height=300,noopener", window);
+ ]]>
+ </script>
+</window>
diff --git a/layout/base/tests/chrome/test_color_scheme_browser.xhtml b/layout/base/tests/chrome/test_color_scheme_browser.xhtml
new file mode 100644
index 0000000000..163f83b38f
--- /dev/null
+++ b/layout/base/tests/chrome/test_color_scheme_browser.xhtml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <head>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/chrome-harness.js"></script>
+ <style>
+ #light { color-scheme: light }
+ #dark { color-scheme: dark }
+ </style>
+ </head>
+ <body>
+ <div id="dynamic-test">
+ <xul:browser type="content" remote="true" nodefaultsrc="true" class="remote" />
+ <xul:browser type="content" src="about:blank" class="nonremote" />
+ </div>
+ <div id="light">
+ <xul:browser type="content" remote="true" nodefaultsrc="true" class="remote" />
+ <xul:browser type="content" src="about:blank" class="nonremote" />
+ </div>
+ <div id="dark">
+ <xul:browser type="content" remote="true" nodefaultsrc="true" class="remote" />
+ <xul:browser type="content" src="about:blank" class="nonremote" />
+ </div>
+ <script><![CDATA[
+ SimpleTest.requestCompleteLog(); // to help diagnose intermittent bug 1787008
+
+ // FIXME: This shouldn't be needed if remote browsers would block the load event.
+ add_task(async function ensureBrowsersLoaded() {
+ info("Entering ensureBrowsersLoaded callback");
+ const triggeringPrincipal = document.nodePrincipal;
+ for (let b of document.querySelectorAll("browser[remote=true]")) {
+ let listener;
+ let loaded = new Promise(resolve => {
+ info("Entering 'loaded' callback; about to add progress listener");
+ listener = {
+ onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
+ info(`Got state change for ${b.parentNode.id}: ${aStateFlags}, ${aStatus}`);
+ if (
+ aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW &&
+ aStateFlags & Ci.nsIWebProgressListener.STATE_STOP
+ ) {
+ resolve();
+ b.removeProgressListener(this);
+ }
+ },
+ // Note: the following "onFoo" callbacks are only here for
+ // diagnostic purposes, and otherwise aren't relevant to the test.
+ onProgressChange(aWebProgress, aRequest,
+ aCurSelfProgress, aMaxSelfProgress,
+ aCurTotalProgress, aMaxTotalProgress) {
+ info(`Got progress change for ${b.parentNode.id}: ` +
+ `${aCurSelfProgress}/${aMaxSelfProgress}, ` +
+ `${aCurTotalProgress}/${aMaxTotalProgress}`);
+ },
+ onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
+ info(`Got location change for ${b.parentNode.id}: ${aLocation.spec}, ${aFlags}`);
+ },
+ onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
+ info(`Got status change for ${b.parentNode.id}: ${aStatus}, ${aMessage}`);
+ },
+ onSecurityChange(aWebProgress, aRequest, aState) {
+ info(`Got security change for ${b.parentNode.id}: ${aState}`);
+ },
+ onContentBlockingEvent(aWebProgress, aRequest, aEvent) {
+ info(`Got content blocking event for ${b.parentNode.id}: ${aEvent}`);
+ },
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIWebProgressListener",
+ "nsISupportsWeakReference",
+ ]),
+ };
+ b.addProgressListener(listener);
+ });
+ info(`Calling b.loadURI for ${b.parentNode.id}`);
+ // Keep the listener alive, since it's a weak ref otherwise.
+ window.ALIVE_LISTENER = listener;
+ b.loadURI(null /*blank*/, { triggeringPrincipal });
+ await loaded;
+ delete window.ALIVE_LISTENER;
+ }
+ });
+ async function getBrowserColorScheme(browser) {
+ return SpecialPowers.spawn(browser, [], () => {
+ return content.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
+ });
+ }
+ async function tick() {
+ return new Promise(resolve => {
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
+ });
+ }
+ async function testElement(id, expectedIfTop, expectedIfNonTop) {
+ let element = document.getElementById(id);
+ for (let browser of element.querySelectorAll("browser")) {
+ let scheme = await getBrowserColorScheme(browser);
+ let expected = browser.browsingContext.top == browser.browsingContext ? expectedIfTop : expectedIfNonTop;
+ is(scheme, expected, `${id}: ${browser.className} should be ${expected}`);
+ }
+ }
+ add_task(async function test_browser_color_scheme() {
+ let current = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
+ for (let id of ["dynamic-test", "light", "dark"]) {
+ let expected = id == "dynamic-test" ? current : id;
+ await testElement(id, expected, expected);
+ }
+ });
+
+ add_task(async function test_browser_color_scheme_dynamic_style() {
+ let current = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
+ let dynamicTest = document.getElementById("dynamic-test");
+ for (let value of ["light", "dark"]) {
+ await tick();
+ dynamicTest.style.colorScheme = value;
+ await testElement("dynamic-test", value, value);
+ }
+ dynamicTest.style.colorScheme = "";
+ await tick();
+ });
+
+ add_task(async function test_browser_color_scheme_dynamic_system() {
+ const ACTIVE_THEME_ID = Services.prefs.getCharPref("extensions.activeThemeID");
+ const DEFAULT_THEME_ID = "default-theme@mozilla.org";
+ if (ACTIVE_THEME_ID != DEFAULT_THEME_ID) {
+ info(`skipping test_browser_color_scheme_dynamic_system because the active theme is ${ACTIVE_THEME_ID} instead of ${DEFAULT_THEME_ID}`);
+ return;
+ }
+ for (let dark of [true, false]) {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["layout.css.prefers-color-scheme.content-override", 2],
+ ["ui.systemUsesDarkTheme", dark ? 1 : 0],
+ ]
+ });
+ await tick();
+ let expected = dark ? "dark" : "light";
+ await testElement("dynamic-test", expected, expected);
+ await SpecialPowers.popPrefEnv();
+ }
+ });
+ ]]></script>
+ </body>
+</html>
+
diff --git a/layout/base/tests/chrome/test_css_visibility_propagation.xhtml b/layout/base/tests/chrome/test_css_visibility_propagation.xhtml
new file mode 100644
index 0000000000..f11db96a89
--- /dev/null
+++ b/layout/base/tests/chrome/test_css_visibility_propagation.xhtml
@@ -0,0 +1,209 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+<body xmlns="http://www.w3.org/1999/xhtml"></body>
+<script>
+<![CDATA[
+const baseURL = "chrome://mochitests/content/chrome/layout/base/tests/chrome/";
+
+function checkHiddenEmbeddederState(window1, window2, expected1, expected2)
+{
+ ok(!window1.browsingContext.isUnderHiddenEmbedderElement, "window1 visible state");
+ ok(!window2.browsingContext.isUnderHiddenEmbedderElement, "window2 visible state");
+ is(window1.document.querySelector("browser").contentWindow.browsingContext.isUnderHiddenEmbedderElement, !expected1,
+ "window1 child visible state");
+ is(window2.document.querySelector("browser").contentWindow.browsingContext.isUnderHiddenEmbedderElement, !expected2,
+ "window2 child visible state");
+}
+
+// Tests that browser visibility is updated when it's swapped.
+add_task(async () => {
+ // Open two new windows to swap iframes.
+ const window1 = window.browsingContext.topChromeWindow.open(
+ baseURL + "window_css_visibility_propagation-1.xhtml",
+ "_blank", "chrome");
+ const window2 = window.browsingContext.topChromeWindow.open(
+ baseURL + "window_css_visibility_propagation-2.xhtml",
+ "_blank", "chrome");
+
+ const loadWindow1 =
+ new Promise(resolve => window1.addEventListener("load", resolve));
+ const loadWindow2 =
+ new Promise(resolve => window2.addEventListener("load", resolve));
+
+ await Promise.all([ loadWindow1, loadWindow2 ]);
+
+ checkHiddenEmbeddederState(window1, window2, false, true);
+
+ // Hide the parent of browser2.
+ let parent = window2.document.getElementById("parent");
+ parent.style.visibility = "hidden";
+ parent.getBoundingClientRect();
+
+ checkHiddenEmbeddederState(window1, window2, false, false);
+
+ const browser2 = window2.document.querySelector("browser");
+ let target = browser2.contentDocument.getElementById("button");
+ target.focus();
+
+ // browser2 is now in a visibility:hidden element in window2,
+ // so that Element.focus() shouldn't work.
+ isnot(browser2.contentDocument.activeElement, target,
+ "Element.focus() shouldn't work in invisible browser");
+
+ // Make the parent visible.
+ parent.style.visibility = "";
+ parent.getBoundingClientRect();
+
+ checkHiddenEmbeddederState(window1, window2, false, true);
+
+ target.focus();
+
+ // browser2 is visible now, so focus() should work.
+ is(browser2.contentDocument.activeElement, target,
+ "Element.focus() should work in visible browser");
+
+ target.blur();
+ isnot(browser2.contentDocument.activeElement, target,
+ "The target element shouldn't be activeElement");
+
+ // Swap the content in browser1 for the content in browser2.
+ const browser1 = window1.document.querySelector("browser");
+ browser1.swapFrameLoaders(browser2);
+ await new Promise(resolve => setTimeout(resolve, 0));
+
+ target = browser1.contentDocument.getElementById("button");
+ target.focus();
+
+ // browser1 is in a visibility:hidden element in window1,
+ // so that Element.focus() shouldn't work.
+ isnot(browser1.contentDocument.activeElement, target,
+ "Element.focus() shouldn't work in invisible browser");
+
+ checkHiddenEmbeddederState(window1, window2, false, true);
+
+ parent = window1.document.getElementById("parent");
+ parent.style.visibility = "visible";
+ parent.getBoundingClientRect();
+
+ checkHiddenEmbeddederState(window1, window2, true, true);
+
+ target.focus();
+
+ // Now browser1 is in a visibility:visible element, so that
+ // Element.focus() should just work.
+ is(browser1.contentDocument.activeElement, target,
+ "Element.focus() should work in visible browser");
+
+ window1.close();
+ window2.close();
+});
+
+// Tests that ancestor's visibility change doesn't clobber child
+// iframe's visibility if the child iframe is hidden by an
+// element in the ancestor document.
+add_task(async () => {
+ const tabReady = new Promise(resolve => {
+ window.addEventListener("message", event => {
+ if (event.data == "ready") {
+ resolve();
+ }
+ }, { once: true });
+ });
+ const tabWindow =
+ window.open(baseURL + "window_css_visibility_propagation-3.html");
+ await tabReady;
+
+ const childIFrame = tabWindow.document.querySelector("iframe");
+
+ const grandChildBrowser =
+ childIFrame.contentDocument.querySelector("browser");
+ let target = grandChildBrowser.contentDocument.getElementById("button");
+ target.focus();
+
+ ok(!tabWindow.browsingContext.isUnderHiddenEmbedderElement, "tab window is visible");
+ ok(!childIFrame.browsingContext.isUnderHiddenEmbedderElement, "iframe is visible");
+ ok(!grandChildBrowser.browsingContext.isUnderHiddenEmbedderElement, "grandchild is visible");
+
+ is(grandChildBrowser.contentDocument.activeElement, target,
+ "Element.focus() should work in visible browser");
+ target.blur();
+
+ // Hide the parent element of the grand child browser.
+ let parent = childIFrame.contentDocument.getElementById("parent");
+ parent.style.visibility = "hidden";
+ parent.getBoundingClientRect();
+
+ ok(!tabWindow.browsingContext.isUnderHiddenEmbedderElement, "tab window is visible");
+ ok(!childIFrame.browsingContext.isUnderHiddenEmbedderElement, "iframe is visible");
+ ok(grandChildBrowser.browsingContext.isUnderHiddenEmbedderElement, "grandchild is not visible");
+
+ target.focus();
+
+ isnot(grandChildBrowser.contentDocument.activeElement, target,
+ "Element.focus() shouldn't work in invisible browser");
+
+ // Hide the parent element of the child iframe.
+ parent = tabWindow.document.getElementById("parent");
+ parent.style.visibility = "hidden";
+ parent.getBoundingClientRect();
+
+ target.focus();
+
+ ok(!tabWindow.browsingContext.isUnderHiddenEmbedderElement, "tab window is visible");
+ ok(childIFrame.browsingContext.isUnderHiddenEmbedderElement, "iframe is not visible");
+ ok(grandChildBrowser.browsingContext.isUnderHiddenEmbedderElement, "grandchild is not visible");
+
+ isnot(grandChildBrowser.contentDocument.activeElement, target,
+ "Element.focus() shouldn't work in invisible iframe");
+
+ // Make the parent element of the child iframe visible.
+ parent.style.visibility = "visible";
+ parent.getBoundingClientRect();
+
+ ok(!tabWindow.browsingContext.isUnderHiddenEmbedderElement, "tab window is visible");
+ ok(!childIFrame.browsingContext.isUnderHiddenEmbedderElement, "iframe is visible");
+ ok(grandChildBrowser.browsingContext.isUnderHiddenEmbedderElement, "grandchild is not visible");
+
+ target.focus();
+
+ // Even if the child iframe is visible, but still the grand child is
+ // hidden by the parent element of the grand child browser so that
+ // we can't focus to the element in the grand child browser.
+ isnot(grandChildBrowser.contentDocument.activeElement, target,
+ "Element.focus() shouldn't work in invisible browser");
+
+ tabWindow.close();
+});
+
+// Tests that an iframe is initially hidden by a visibility:hidden element in
+// the parent document.
+add_task(async () => {
+ const tabReady = new Promise(resolve => {
+ window.addEventListener("message", event => {
+ if (event.data == "ready") {
+ resolve();
+ }
+ }, { once: true });
+ });
+ const tabWindow =
+ window.open(baseURL + "window_css_visibility_propagation-4.html");
+ await tabReady;
+
+ const iframe = tabWindow.document.querySelector("iframe");
+ let target = iframe.contentDocument.getElementById("button");
+ target.focus();
+
+ ok(!tabWindow.browsingContext.isUnderHiddenEmbedderElement, "tab window is visible");
+ ok(iframe.browsingContext.isUnderHiddenEmbedderElement, "iframe is not visible");
+
+ isnot(iframe.contentDocument.activeElement, target,
+ "Element.focus() shouldn't work in invisible iframe");
+
+ tabWindow.close();
+});
+]]>
+</script>
+</window>
diff --git a/layout/base/tests/chrome/test_default_background.xhtml b/layout/base/tests/chrome/test_default_background.xhtml
new file mode 100644
index 0000000000..26e28c574e
--- /dev/null
+++ b/layout/base/tests/chrome/test_default_background.xhtml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ SimpleTest.waitForExplicitFinish();
+ // Run the test in a separate window so that the test runs as a chrome
+ // window
+ window.openDialog("default_background_window.xhtml", "default_background",
+ "chrome,width=200,height=300,noopener", window);
+ ]]>
+ </script>
+</window>
diff --git a/layout/base/tests/chrome/test_dialog_with_positioning.html b/layout/base/tests/chrome/test_dialog_with_positioning.html
new file mode 100644
index 0000000000..db08a3d9b4
--- /dev/null
+++ b/layout/base/tests/chrome/test_dialog_with_positioning.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test positioning of fixed-pos/abs-pos elements in a XUL dialog</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/chrome-harness.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var root = getRootDirectory(window.location.href);
+window.openDialog(root + "dialog_with_positioning_window.xhtml", "dialog_with_positioning",
+ "dialog,chrome,noopener", window);
+</script>
+</pre>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_document_adopted_styles.html b/layout/base/tests/chrome/test_document_adopted_styles.html
new file mode 100644
index 0000000000..f2784bd60b
--- /dev/null
+++ b/layout/base/tests/chrome/test_document_adopted_styles.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset="utf-8">
+<div class="target"></div>
+<script>
+ const sheet = new CSSStyleSheet();
+ document.adoptedStyleSheets = [sheet];
+ sheet.replaceSync(".target { width: 100px; height: 100px; border-style: solid; border-color: blue; }");
+</script>
diff --git a/layout/base/tests/chrome/test_document_adopted_styles_ref.html b/layout/base/tests/chrome/test_document_adopted_styles_ref.html
new file mode 100644
index 0000000000..0b592207f3
--- /dev/null
+++ b/layout/base/tests/chrome/test_document_adopted_styles_ref.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<meta charset="utf-8">
+<body>
+ <div class="target"></div>
+ <style> .target { width: 100px; height: 100px; border-style: solid; border-color: blue; } </style>
+</body>
diff --git a/layout/base/tests/chrome/test_fixed_bg_scrolling_repaints.html b/layout/base/tests/chrome/test_fixed_bg_scrolling_repaints.html
new file mode 100644
index 0000000000..9543340d6b
--- /dev/null
+++ b/layout/base/tests/chrome/test_fixed_bg_scrolling_repaints.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that we don't get unnecessary repaints with fixed backgrounds</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<!-- Need a timeout here to allow paint unsuppression before we start the test -->
+<body onload="setTimeout(startTest,0)" style="background:url(blue-32x32.png) top left no-repeat fixed; background-size: 100px 2000px; overflow:hidden;">
+<div style="height: 2048px"></div>
+
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var utils = window.windowUtils;
+
+function startTest() {
+ // Do a scroll to ensure we trigger activity heuristics.
+ document.documentElement.scrollTop = 1;
+ waitForAllPaintsFlushed(function () {
+ document.documentElement.scrollTop = 0;
+ waitForAllPaintsFlushed(function () {
+ // Clear paint state and scroll down
+ utils.checkAndClearPaintedState(document.documentElement);
+ document.documentElement.scrollTop = 100;
+ waitForAllPaintsFlushed(function () {
+ // Make sure nothing painted
+ var painted = utils.checkAndClearPaintedState(document.documentElement);
+ is(painted, false, "Fixed background should not have been painted when scrolled");
+ SimpleTest.finish();
+ });
+ });
+ });
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_getClientRectsAndTexts.html b/layout/base/tests/chrome/test_getClientRectsAndTexts.html
new file mode 100644
index 0000000000..d2fdde2197
--- /dev/null
+++ b/layout/base/tests/chrome/test_getClientRectsAndTexts.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<div id="div1" style="width:200px">Here is some text that <a href="#">will wrap</a> in <a href="#">this small</a>-ish container.</div>
+<div id="div2">Into another <a href="#">container</a></div>
+<div id="div3">A very <span>deep <span>deep <span>deep</span></span></span> bit of text.</div>
+
+<script>
+if (typeof(is) == "undefined") {
+ var is = function(a, b, m) {
+ if(a != b) {
+ window.console.log("Expected '" + b + "' but got '" + a + "': " + m);
+ }
+ };
+}
+
+if (typeof(todo_is) == "undefined") {
+ var todo_is = is;
+}
+
+function testRangeTexts(startNode, startOffset, endNode, endOffset, expectedText, todo) {
+ let r = new Range();
+ r.setStart(startNode, startOffset);
+ r.setEnd(endNode, endOffset);
+
+ let texts = r.getClientRectsAndTexts().textList;
+ let concatText = "";
+ for (let i = 0; i < texts.length; i++) {
+ concatText += texts[i];
+ }
+
+ if (todo) {
+ todo_is(concatText, expectedText, "Text matches.");
+ } else {
+ is(concatText, expectedText, "Text matches.");
+ }
+}
+
+let d1c1 = div1.firstChild;
+let d1c2 = d1c1.nextSibling;
+let d1c3 = d1c2.nextSibling;
+let d1c4 = d1c3.nextSibling;
+let d1c5 = d1c4.nextSibling;
+
+let link1 = d1c2.firstChild;
+let link2 = d1c4.firstChild;
+
+let d2c1 = div2.firstChild;
+let d2c2 = d2c1.nextSibling;
+
+let link3 = d2c2.firstChild;
+
+let d3c1 = div3.firstChild;
+let d3c2 = d3c1.nextSibling;
+let d3c3 = d3c2.nextSibling;
+
+let data = [
+ [d1c1, 0, d1c1, 0, ""],
+ [d1c1, 0, d1c1, 4, "Here"],
+ [d1c1, 4, d1c1, 7, " is"],
+ [d1c1, 22, link1, 0, " "],
+ [d1c1, 22, link1, 1, " w"],
+ [d1c1, 22, d1c3, 1, " will wrap "],
+ [link1, 2, link2, 3, "ll wrap in thi"],
+ [link2, 5, link3, 3, "small-ish container.Into another con"],
+ [d3c1, 3, d3c3, 4, "ery deep deep deep bit"],
+];
+
+data.forEach(function (d) { testRangeTexts.apply(null, d); });
+
+</script>
+
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_get_printer_basic_attributes.html b/layout/base/tests/chrome/test_get_printer_basic_attributes.html
new file mode 100644
index 0000000000..26a04e09d5
--- /dev/null
+++ b/layout/base/tests/chrome/test_get_printer_basic_attributes.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body onload="run()">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+async function run() {
+ try {
+ let printerList = Cc["@mozilla.org/gfx/printerlist;1"].getService(
+ Ci.nsIPrinterList
+ );
+
+ let printers = await printerList.printers;
+ for (let printer of printers) {
+ printer.QueryInterface(Ci.nsIPrinter);
+ info(`Listing basic attributes for ${printer.name}:`);
+ let [supportsDuplex, supportsColor] = await Promise.all([printer.supportsDuplex, printer.supportsColor]);
+ info(`* supportsDuplex: ${supportsDuplex}`);
+ info(`* supportsColor: ${supportsColor}`);
+ }
+
+ ok(true, "Retrieved printer basic attributes successfully.");
+ } catch (e) {
+ ok(false, `Error thrown while retrieving printer basic attributes: ${e}.`);
+ console.error(e);
+ }
+ SimpleTest.finish();
+}
+
+</script>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_get_printer_orientation.html b/layout/base/tests/chrome/test_get_printer_orientation.html
new file mode 100644
index 0000000000..1bb50eef65
--- /dev/null
+++ b/layout/base/tests/chrome/test_get_printer_orientation.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body onload="run()">
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+async function run() {
+ try {
+ let printerList = Cc["@mozilla.org/gfx/printerlist;1"].getService(
+ Ci.nsIPrinterList
+ );
+ var settingsSvc = Cc["@mozilla.org/gfx/printsettings-service;1"].getService(
+ Ci.nsIPrintSettingsService
+ );
+
+ let printers = await printerList.printers;
+ for (let printer of printers) {
+ printer.QueryInterface(Ci.nsIPrinter);
+ let printerInfo = await printer.printerInfo;
+
+ // Look up the printer's defaultSettings:
+ let defaultSettings = printerInfo.defaultSettings;
+
+ // Let the printer impose its defaults onto a fresh settings object:
+ let freshSettings = settingsSvc.createNewPrintSettings();
+ printerList.initPrintSettingsFromPrinter(printer.name, freshSettings);
+
+ // Make sure they agree on the default orientation:
+ is(freshSettings.orientation, defaultSettings.orientation,
+ "initPrintSettingsFromPrinter should produce the same orientation " +
+ "as the printer's defaultSettings");
+ }
+
+ // This ok() just lets us avoid failure-due-to-no-tests-being-run, on
+ // devices that have no printers available & hence skip the loop above:
+ ok(true, "Finished traversing printers.");
+ } catch (e) {
+ ok(false, `Error thrown while retrieving printer info: ${e}.`);
+ console.error(e);
+ }
+ SimpleTest.finish();
+}
+
+</script>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_get_printer_paper_sizes.html b/layout/base/tests/chrome/test_get_printer_paper_sizes.html
new file mode 100644
index 0000000000..4ebe462ac6
--- /dev/null
+++ b/layout/base/tests/chrome/test_get_printer_paper_sizes.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body onload="run()">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+async function run() {
+ try {
+ let printerList = Cc["@mozilla.org/gfx/printerlist;1"].getService(
+ Ci.nsIPrinterList
+ );
+ let printers = await printerList.printers;
+ if (printers.length == 0) {
+ ok(true, "There were no printers to iterate through.");
+ }
+
+ for (let printer of printers) {
+ printer.QueryInterface(Ci.nsIPrinter);
+ is(typeof(printer.name), 'string', "Printer name should be a string.");
+ isnot(printer.name, "", "Printer name should never be empty.");
+
+ info(printer.name);
+ info("duplex(" + printer.supportsDuplex + ")");
+
+ let printerInfo = await printer.printerInfo;
+ for (let paper of printerInfo.paperList) {
+ paper.QueryInterface(Ci.nsIPaper);
+
+ info(`${paper.name}: ${paper.width}x${paper.height}`);
+
+ is(typeof(paper.name), 'string', "Paper name should be a string.");
+ isnot(paper.name, "", "Paper name should never be empty.");
+
+ is(typeof(paper.width), 'number', "Paper width should be a number.");
+ ok(paper.width > 0.0, "Paper width should be greater than zero.");
+
+ is(typeof(paper.height), 'number', "Paper height should be a number.");
+ ok(paper.height > 0.0, "Paper height should be greater than zero.");
+
+ let margin = await paper.unwriteableMargin;
+ margin.QueryInterface(Ci.nsIPaperMargin);
+
+ info(`with margin: ${margin.top} ${margin.right} ${margin.bottom} ${margin.left}`);
+
+ is(typeof(margin.top), 'number', "Paper unwriteable margin top should be a number.");
+ is(typeof(margin.right), 'number', "Paper unwriteable margin right should be a number.");
+ is(typeof(margin.bottom), 'number', "Paper unwriteable margin bottom should be a number.");
+ is(typeof(margin.left), 'number', "Paper unwriteable margin left should be a number.");
+
+ ok(margin.top >= 0.0, "Paper unwriteable margin top should be greater than or equal to zero.");
+ ok(margin.right >= 0.0, "Paper unwriteable margin right should be greater than or equal to zero.");
+ ok(margin.bottom >= 0.0, "Paper unwriteable bottom right should be greater than or equal to zero.");
+ ok(margin.left >= 0.0, "Paper unwriteable margin left should be greater than or equal to zero.");
+ }
+ }
+ } catch (e) {
+ ok(false, `Shouldn't throw: ${e}`);
+ console.error(e);
+ }
+ SimpleTest.finish();
+}
+
+</script>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_prerendered_transforms.html b/layout/base/tests/chrome/test_prerendered_transforms.html
new file mode 100644
index 0000000000..d8b8c8bcfd
--- /dev/null
+++ b/layout/base/tests/chrome/test_prerendered_transforms.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that active transformed elements coming into view are prerendered so we don't have to redraw constantly</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body onload="startTest()">
+<div>
+<div id="t" style="position:absolute; left:0; top:500px; transform: translatex(-100px); width:200px; height:100px; background:yellow;">
+ <div style="text-align:right">Hello</div>
+ <div style="text-align:left">Kitty</div>
+</div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var t = document.getElementById("t");
+var utils = window.windowUtils;
+
+function startTest() {
+ // Do a couple of transform changes to ensure we've triggered activity heuristics
+ waitForAllPaintsFlushed(function () {
+ t.style.transform = "translatex(-75px)";
+ waitForAllPaintsFlushed(function () {
+ t.style.transform = "translatex(-50px)";
+ waitForAllPaintsFlushed(function () {
+ // Clear paint state now and move again.
+ utils.checkAndClearPaintedState(t);
+ // Don't move to 0 since that might trigger some special case that turns off transforms.
+ t.style.transform = "translatex(-1px)";
+ waitForAllPaintsFlushed(function () {
+ var painted = utils.checkAndClearPaintedState(t);
+ is(painted, false, "Transformed element should not have been painted");
+ SimpleTest.finish();
+ });
+ });
+ });
+ });
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_printer_default_settings.html b/layout/base/tests/chrome/test_printer_default_settings.html
new file mode 100644
index 0000000000..8fb6f98a4e
--- /dev/null
+++ b/layout/base/tests/chrome/test_printer_default_settings.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body onload="run()">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+async function run() {
+ try {
+ let printerList = Cc["@mozilla.org/gfx/printerlist;1"].getService(
+ Ci.nsIPrinterList
+ );
+ let printers = await printerList.printers;
+ if (printers.length == 0) {
+ ok(true, "There were no printers to iterate through.");
+ }
+
+ for (let printer of printers) {
+ printer.QueryInterface(Ci.nsIPrinter);
+ info(printer.name);
+ info("duplex(" + await printer.supportsDuplex + ")");
+
+ const printerInfo = await printer.printerInfo;
+ const settings = printerInfo.defaultSettings;
+ settings.QueryInterface(Ci.nsIPrintSettings);
+
+ is(typeof settings.printerName, "string", "Printer name should be a string.");
+ is(settings.printerName, printer.name, "Print settings' printer should match the printer that created them.");
+
+ is(typeof settings.paperId, "string", "Paper ID should never be null.");
+ is(typeof settings.paperWidth, "number", "Paper width should never be null.");
+ is(typeof settings.paperHeight, "number", "Paper height should never be null.");
+
+ if (settings.paperId != "") {
+ info(`Paper: ${settings.paperId}`);
+ info(`Size: (${settings.paperWidth} x ${settings.paperHeight})`);
+ ok(settings.paperWidth > 0.0, "Paper width should be greater than zero.");
+ ok(settings.paperHeight > 0.0, "Paper height should be greater than zero.");
+ }
+
+ ok(settings.marginTop >= 0.0, "Paper margins should be greater than or equal to zero.");
+ ok(settings.marginRight >= 0.0, "Paper margins should be greater than or equal to zero.");
+ ok(settings.marginBottom >= 0.0, "Paper margins should be greater than or equal to zero.");
+ ok(settings.marginLeft >= 0.0, "Paper margins should be greater than or equal to zero.");
+
+ is(settings.printInColor, await printer.supportsColor, "Print settings' color mode should match the printer's color support.");
+
+ ok(settings.isInitializedFromPrinter, "Print settings were initialized from printer");
+ ok(!settings.isInitializedFromPrefs);
+ }
+ } catch (e) {
+ ok(false, `Shouldn't throw: ${e}`);
+ console.error(e);
+ }
+ SimpleTest.finish();
+}
+
+</script>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_printpreview.xhtml b/layout/base/tests/chrome/test_printpreview.xhtml
new file mode 100644
index 0000000000..c63d7a62d1
--- /dev/null
+++ b/layout/base/tests/chrome/test_printpreview.xhtml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<body xmlns="http://www.w3.org/1999/xhtml">
+</body>
+ <!-- test code goes here -->
+<script type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestLongerTimeout(3);
+window.openDialog("printpreview_helper.xhtml", "printpreview", "chrome,width=100,height=100,noopener", window);
+]]></script>
+</window>
diff --git a/layout/base/tests/chrome/test_printpreview_bug396024.xhtml b/layout/base/tests/chrome/test_printpreview_bug396024.xhtml
new file mode 100644
index 0000000000..4b839f3b2b
--- /dev/null
+++ b/layout/base/tests/chrome/test_printpreview_bug396024.xhtml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=396024
+-->
+<window title="Mozilla Bug 369024"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=396024"
+ target="_blank">Mozilla Bug 396024</a>
+</body>
+ <!-- test code goes here -->
+<script type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+window.openDialog("printpreview_bug396024_helper.xhtml", "bug396024", "chrome,width=100,height=100,noopener", window);
+]]></script>
+</window>
diff --git a/layout/base/tests/chrome/test_printpreview_bug482976.xhtml b/layout/base/tests/chrome/test_printpreview_bug482976.xhtml
new file mode 100644
index 0000000000..8dd4c65337
--- /dev/null
+++ b/layout/base/tests/chrome/test_printpreview_bug482976.xhtml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=482976
+-->
+<window title="Mozilla Bug 482976"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=482976"
+ target="_blank">Mozilla Bug 482976</a>
+</body>
+ <!-- test code goes here -->
+<script type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+window.openDialog("printpreview_bug482976_helper.xhtml", "bug482976", "chrome,width=100,height=100,noopener", window);
+]]></script>
+</window>
diff --git a/layout/base/tests/chrome/test_scrolling_repaints.html b/layout/base/tests/chrome/test_scrolling_repaints.html
new file mode 100644
index 0000000000..605e598c52
--- /dev/null
+++ b/layout/base/tests/chrome/test_scrolling_repaints.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that we don't get unnecessary repaints due to subpixel shifts</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<!-- Need a timeout here to allow paint unsuppression before we start the test -->
+<body onload="setTimeout(startTest,0)">
+<div id="t" style="width:400px; height:100px; background:yellow; overflow:hidden">
+ <div style="height:40px;"></div>
+ <div id="e" style="height:30px; background:lime"></div>
+ <div style="height:60.4px; background:pink"></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var t = document.getElementById("t");
+var e = document.getElementById("e");
+var utils = window.windowUtils;
+
+function startTest() {
+ // Do a scroll to ensure we trigger activity heuristics.
+ waitForAllPaintsFlushed(function () {
+ t.scrollTop = 5;
+ // Scroll down as far as we can, to put our rendering layer at a subpixel offset within the layer
+ waitForAllPaintsFlushed(function () {
+ t.scrollTop = 1000;
+ waitForAllPaintsFlushed(function () {
+ // Clear paint state now and scroll again.
+ utils.checkAndClearPaintedState(e);
+ // scroll up a little bit. This should not cause anything to be repainted.
+ t.scrollTop = t.scrollTop - 10;
+ waitForAllPaintsFlushed(function () {
+ var painted = utils.checkAndClearPaintedState(e);
+ is(painted, false, "Fully-visible scrolled element should not have been painted");
+ SimpleTest.finish();
+ });
+ });
+ });
+ });
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/layout/base/tests/chrome/test_shadow_root_adopted_styles.html b/layout/base/tests/chrome/test_shadow_root_adopted_styles.html
new file mode 100644
index 0000000000..d6701f3089
--- /dev/null
+++ b/layout/base/tests/chrome/test_shadow_root_adopted_styles.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<meta charset="utf-8">
+<body>
+<script>
+ document.body.attachShadow({mode: "open"}).innerHTML = `
+ <div class="target"></div>
+ `;
+ const sheet = new CSSStyleSheet();
+ document.body.shadowRoot.adoptedStyleSheets = [sheet];
+ sheet.replaceSync(".target { width: 100px; height: 100px; border-style: solid; border-color: blue; }");
+</script>
diff --git a/layout/base/tests/chrome/test_shadow_root_adopted_styles_ref.html b/layout/base/tests/chrome/test_shadow_root_adopted_styles_ref.html
new file mode 100644
index 0000000000..fae4a54f21
--- /dev/null
+++ b/layout/base/tests/chrome/test_shadow_root_adopted_styles_ref.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<meta charset="utf-8">
+<body>
+<script>
+ document.body.attachShadow({mode: "open"}).innerHTML = `
+ <div class="target"></div>
+ <style>
+ .target { width: 100px; height: 100px; border-style: solid; border-color: blue; }
+ </style>
+ `;
+</script>
diff --git a/layout/base/tests/chrome/test_shared_adopted_styles.html b/layout/base/tests/chrome/test_shared_adopted_styles.html
new file mode 100644
index 0000000000..f5b232bce6
--- /dev/null
+++ b/layout/base/tests/chrome/test_shared_adopted_styles.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<meta charset="utf-8">
+<body>
+ <div class="target"></div>
+ <span id="shadowHostA"></span>
+ <span id="shadowHostB"></span>
+</body>
+<script>
+ const sheet = new CSSStyleSheet();
+ sheet.replaceSync(".target { width: 100px; height: 100px; border-style: solid; border-color: blue; }");
+
+ const innerHTMLText = `<div class="target"></div>`
+ shadowHostA.attachShadow({mode: "open"}).innerHTML = innerHTMLText;
+ shadowHostB.attachShadow({mode: "open"}).innerHTML = innerHTMLText;
+
+ document.adoptedStyleSheets = [sheet];
+ shadowHostA.shadowRoot.adoptedStyleSheets = [sheet];
+ shadowHostB.shadowRoot.adoptedStyleSheets = [sheet];
+</script>
diff --git a/layout/base/tests/chrome/test_shared_adopted_styles_ref.html b/layout/base/tests/chrome/test_shared_adopted_styles_ref.html
new file mode 100644
index 0000000000..b12cb5fd99
--- /dev/null
+++ b/layout/base/tests/chrome/test_shared_adopted_styles_ref.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<meta charset="utf-8">
+<body>
+ <div class="target"></div>
+ <span id="shadowHostA"></span>
+ <span id="shadowHostB"></span>
+ <style> .target { width: 100px; height: 100px; border-style: solid; border-color: blue; } </style>
+</body>
+<script>
+ const innerHTMLText = `
+ <div class="target"></div>
+ <style> .target { width: 100px; height: 100px; border-style: solid; border-color: blue; } </style>
+ `;
+ shadowHostA.attachShadow({mode: "open"}).innerHTML = innerHTMLText;
+ shadowHostB.attachShadow({mode: "open"}).innerHTML = innerHTMLText;
+</script>
diff --git a/layout/base/tests/chrome/test_will_change.html b/layout/base/tests/chrome/test_will_change.html
new file mode 100644
index 0000000000..fd34dc50f6
--- /dev/null
+++ b/layout/base/tests/chrome/test_will_change.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Tests for MozAfterPaint</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"></script>
+ <style>
+ div {
+ width: 100px;
+ height: 100px;
+ background: radial-gradient(ellipse at center, #87e0fd 0%,#53cbf1 40%,#05abe0 100%);
+ }
+ </style>
+</head>
+<body>
+</body>
+<script>
+
+var utils = window.windowUtils;
+
+function waitForPaints() {
+ return new Promise(function(resolve, reject) {
+ waitForAllPaintsFlushed(resolve);
+ });
+}
+
+add_task(async () => {
+ var element = document.createElement("div");
+ document.body.appendChild(element);
+
+ await waitForPaints();
+
+ utils.checkAndClearPaintedState(element);
+ element.style.opacity = "0.5";
+
+ await waitForPaints();
+
+ var painted = utils.checkAndClearPaintedState(element);
+ // *** We check that this repaints because the test is relying
+ // on this property. If this is broken then this test wont
+ // be reliable check for will-change.
+ is(painted, true, "element should have been painted");
+
+ element.remove();
+});
+
+add_task(async () => {
+ var element = document.createElement("div");
+ document.body.appendChild(element);
+
+ element.style.willChange = "opacity";
+
+ await waitForPaints();
+
+ utils.checkAndClearPaintedState(element);
+ element.style.opacity = "0.5";
+
+ await waitForPaints();
+
+ var painted = utils.checkAndClearPaintedState(element);
+ // BasicLayers' heuristics are so that even with will-change:opacity,
+ // we can still have repaints.
+ if (utils.layerManagerType != "Basic") {
+ is(painted, false, "will-change:opacity element should not have been painted");
+ }
+
+ element.remove();
+});
+
+add_task(async () => {
+ var element = document.createElement("div");
+ document.body.appendChild(element);
+
+ element.style.willChange = "transform";
+
+ await waitForPaints();
+
+ utils.checkAndClearPaintedState(element);
+ element.style.transform = "translateY(-5px)";
+
+ await waitForPaints();
+
+ var painted = utils.checkAndClearPaintedState(element);
+ // BasicLayers' heuristics are so that even with will-change:transform,
+ // we can still have repaints.
+ if (utils.layerManagerType != "Basic") {
+ is(painted, false, "will-change:transform element should not have been painted");
+ }
+
+ element.remove();
+});
+
+add_task(async () => {
+ var element = document.createElement("div");
+ document.body.appendChild(element);
+
+ element.style.willChange = "translate";
+
+ await waitForPaints();
+
+ utils.checkAndClearPaintedState(element);
+ element.style.translate = "5px";
+
+ await waitForPaints();
+
+ var painted = utils.checkAndClearPaintedState(element);
+ // BasicLayers' heuristics are so that even with will-change:translate,
+ // we can still have repaints.
+ if (utils.layerManagerType != "Basic") {
+ is(painted, false, "will-change:translate element should not have been painted");
+ }
+
+ element.remove();
+});
+
+add_task(async () => {
+ var element = document.createElement("div");
+ document.body.appendChild(element);
+
+ element.style.willChange = "offset-path";
+
+ await waitForPaints();
+
+ utils.checkAndClearPaintedState(element);
+ element.style.offsetPath = "path('M55 50 h1')";
+
+ await waitForPaints();
+
+ var painted = utils.checkAndClearPaintedState(element);
+ // BasicLayers' heuristics are so that even with will-change:offset-path,
+ // we can still have repaints.
+ if (utils.layerManagerType != "Basic") {
+ is(painted, false, "will-change:offset-path element should not have been painted");
+ }
+
+ element.remove();
+});
+
+</script>
+</html>
diff --git a/layout/base/tests/chrome/window_css_visibility_propagation-1.xhtml b/layout/base/tests/chrome/window_css_visibility_propagation-1.xhtml
new file mode 100644
index 0000000000..ac9c63ec14
--- /dev/null
+++ b/layout/base/tests/chrome/window_css_visibility_propagation-1.xhtml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<div id="parent" style="visibility:hidden">
+ <browser type="content" src="about:mozilla"></browser>
+</div>
+</window>
diff --git a/layout/base/tests/chrome/window_css_visibility_propagation-2.xhtml b/layout/base/tests/chrome/window_css_visibility_propagation-2.xhtml
new file mode 100644
index 0000000000..9b9e42c2d1
--- /dev/null
+++ b/layout/base/tests/chrome/window_css_visibility_propagation-2.xhtml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<div id="parent">
+ <browser type="content" src="frame_css_visibility_propagation.html"></browser>
+</div>
+</window>
diff --git a/layout/base/tests/chrome/window_css_visibility_propagation-3.html b/layout/base/tests/chrome/window_css_visibility_propagation-3.html
new file mode 100644
index 0000000000..91a2230ee1
--- /dev/null
+++ b/layout/base/tests/chrome/window_css_visibility_propagation-3.html
@@ -0,0 +1,3 @@
+<div id="parent">
+ <iframe onload="opener.postMessage('ready');" src="window_css_visibility_propagation-2.xhtml"/>
+</div>
diff --git a/layout/base/tests/chrome/window_css_visibility_propagation-4.html b/layout/base/tests/chrome/window_css_visibility_propagation-4.html
new file mode 100644
index 0000000000..98de74059c
--- /dev/null
+++ b/layout/base/tests/chrome/window_css_visibility_propagation-4.html
@@ -0,0 +1,3 @@
+<div id="parent" style="visibility:hidden">
+ <iframe onload="opener.postMessage('ready');" src="frame_css_visibility_propagation.html"/>
+</div>