From ca4fa236261ef33e13974ef635171f27551b7d9f Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 24 Mar 2020 22:54:18 +0000 Subject: [PATCH] Bug 1621415 - Ensure adopted styles are applied when printing r=emilio - Add functionality to clone adopted style sheets for printing. - Add reftest to ensure that the document's adopted styles show in print. - Add reftest to ensure that a shadow root's adopted styles show in print. Differential Revision: https://phabricator.services.mozilla.com/D66517 --HG-- extra : moz-landing-system : lando --- dom/base/Document.cpp | 1 + dom/base/DocumentOrShadowRoot.cpp | 21 ++++++++++++++ dom/base/DocumentOrShadowRoot.h | 6 ++++ dom/base/ShadowRoot.cpp | 1 + layout/base/tests/chrome/chrome.ini | 5 ++++ .../tests/chrome/printpreview_helper.xhtml | 28 +++++++++++++++---- .../chrome/test_document_adopted_styles.html | 8 ++++++ .../test_document_adopted_styles_ref.html | 6 ++++ .../test_shadow_root_adopted_styles.html | 11 ++++++++ .../test_shadow_root_adopted_styles_ref.html | 11 ++++++++ layout/style/StyleSheet.cpp | 17 +++++++++++ layout/style/StyleSheet.h | 7 +++++ 12 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 layout/base/tests/chrome/test_document_adopted_styles.html create mode 100644 layout/base/tests/chrome/test_document_adopted_styles_ref.html create mode 100644 layout/base/tests/chrome/test_shadow_root_adopted_styles.html create mode 100644 layout/base/tests/chrome/test_shadow_root_adopted_styles_ref.html diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index cad289b3b1b0..8703f6940a8a 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -12076,6 +12076,7 @@ already_AddRefed Document::CreateStaticClone( } } } + clonedDoc->CloneAdoptedSheetsFrom(*this); for (int t = 0; t < AdditionalSheetTypeCount; ++t) { auto& sheets = mAdditionalSheets[additionalSheetType(t)]; diff --git a/dom/base/DocumentOrShadowRoot.cpp b/dom/base/DocumentOrShadowRoot.cpp index a15efda70ed3..062fd9efc2b4 100644 --- a/dom/base/DocumentOrShadowRoot.cpp +++ b/dom/base/DocumentOrShadowRoot.cpp @@ -198,6 +198,27 @@ void DocumentOrShadowRoot::ClearAdoptedStyleSheets() { mAdoptedStyleSheets.Clear(); } +void DocumentOrShadowRoot::CloneAdoptedSheetsFrom( + DocumentOrShadowRoot& aSource) { + Document& ownerDoc = *AsNode().OwnerDoc(); + Sequence> list; + if (!list.SetCapacity(mAdoptedStyleSheets.Length(), fallible)) { + return; + } + + // TODO(nordzilla, bug 1621415) We can improve the performance here. + // https://bugzilla.mozilla.org/show_bug.cgi?id=1622322 + for (auto& sheet : aSource.mAdoptedStyleSheets) { + DebugOnly succeeded = + list.AppendElement(sheet->CloneAdoptedSheet(ownerDoc), fallible); + MOZ_ASSERT(succeeded); + } + + ErrorResult rv; + SetAdoptedStyleSheets(list, rv); + MOZ_ASSERT(!rv.Failed()); +} + Element* DocumentOrShadowRoot::GetElementById(const nsAString& aElementId) { if (MOZ_UNLIKELY(aElementId.IsEmpty())) { nsContentUtils::ReportEmptyGetElementByIdArg(AsNode().OwnerDoc()); diff --git a/dom/base/DocumentOrShadowRoot.h b/dom/base/DocumentOrShadowRoot.h index d86a011bc656..a63ed087baa1 100644 --- a/dom/base/DocumentOrShadowRoot.h +++ b/dom/base/DocumentOrShadowRoot.h @@ -245,6 +245,12 @@ class DocumentOrShadowRoot { void RemoveSheetFromStylesIfApplicable(StyleSheet&); void ClearAdoptedStyleSheets(); + /** + * Clone's the argument's adopted style sheets into this. + * This should only be used when cloning a static document for printing. + */ + void CloneAdoptedSheetsFrom(DocumentOrShadowRoot&); + // Returns the reference to the sheet, if found in mStyleSheets. already_AddRefed RemoveSheet(StyleSheet& aSheet); void InsertSheetAt(size_t aIndex, StyleSheet& aSheet); diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp index a7bbab686f25..9fec35441d5d 100644 --- a/dom/base/ShadowRoot.cpp +++ b/dom/base/ShadowRoot.cpp @@ -107,6 +107,7 @@ void ShadowRoot::CloneInternalDataFrom(ShadowRoot* aOther) { } } } + CloneAdoptedSheetsFrom(*aOther); } nsresult ShadowRoot::Bind() { diff --git a/layout/base/tests/chrome/chrome.ini b/layout/base/tests/chrome/chrome.ini index fbc4204f2b60..502720a32a72 100644 --- a/layout/base/tests/chrome/chrome.ini +++ b/layout/base/tests/chrome/chrome.ini @@ -1,5 +1,6 @@ [DEFAULT] prefs = + layout.css.constructable-stylesheets.enabled=true layout.css.individual-transform.enabled=true layout.css.motion-path.enabled=true plugin.load_flash_only=false @@ -21,6 +22,10 @@ support-files = printpreview_font_mozprintcallback_ref.html printpreview_quirks.html printpreview_quirks_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 file_bug1018265.xhtml [test_bug396367-1.html] diff --git a/layout/base/tests/chrome/printpreview_helper.xhtml b/layout/base/tests/chrome/printpreview_helper.xhtml index 6190c47492d4..3b6617429103 100644 --- a/layout/base/tests/chrome/printpreview_helper.xhtml +++ b/layout/base/tests/chrome/printpreview_helper.xhtml @@ -31,7 +31,7 @@ function printpreview(hasMozPrintCallback) { gWbp = frameElts[1].docShell.initOrReusePrintPreviewViewer(); var listener = { onLocationChange: function(webProgress, request, location, flags) { }, - onProgressChange: function(webProgress, request, curSelfProgress, + onProgressChange: function(webProgress, request, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) { }, onSecurityChange: function(webProgress, request, state) { }, @@ -100,10 +100,14 @@ function runTests() } function compareCanvases() { - return window.windowUtils - .compareCanvases(document.getElementsByTagName("canvas")[0], - document.getElementsByTagName("canvas")[1], - {}) == 0; + const canvas1 = document.getElementsByTagName("canvas")[0]; + const canvas2 = document.getElementsByTagName("canvas")[1]; + const result = window.windowUtils.compareCanvases(canvas1, canvas2, {}) == 0; + if (!result) { + todo(false, "TEST CASE: " + canvas1.toDataURL()); + todo(false, "REFERENCE: " + canvas2.toDataURL()); + } + return result; } function addHTMLContent(parent) { @@ -422,8 +426,20 @@ async function runTest11() { requestAnimationFrame(function() { setTimeout(runTest12); } ); } -// Crash test for bug 1615261 +// 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); } ); +} + +// Crash test for bug 1615261 +async function runTest14() { frameElts[0].contentDocument.body.innerHTML = '' + '
Firefox will crash if you try and print this page
'; 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 000000000000..f2784bd60b0b --- /dev/null +++ b/layout/base/tests/chrome/test_document_adopted_styles.html @@ -0,0 +1,8 @@ + + +
+ 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 000000000000..0b592207f355 --- /dev/null +++ b/layout/base/tests/chrome/test_document_adopted_styles_ref.html @@ -0,0 +1,6 @@ + + + +
+ + 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 000000000000..d6701f308999 --- /dev/null +++ b/layout/base/tests/chrome/test_shadow_root_adopted_styles.html @@ -0,0 +1,11 @@ + + + + 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 000000000000..fae4a54f21b6 --- /dev/null +++ b/layout/base/tests/chrome/test_shadow_root_adopted_styles_ref.html @@ -0,0 +1,11 @@ + + + + diff --git a/layout/style/StyleSheet.cpp b/layout/style/StyleSheet.cpp index 3e615d6af239..1a7809a7d372 100644 --- a/layout/style/StyleSheet.cpp +++ b/layout/style/StyleSheet.cpp @@ -1321,12 +1321,29 @@ already_AddRefed StyleSheet::Clone( StyleSheet* aCloneParent, dom::CSSImportRule* aCloneOwnerRule, dom::DocumentOrShadowRoot* aCloneDocumentOrShadowRoot, nsINode* aCloneOwningNode) const { + MOZ_ASSERT(!IsConstructed(), + "Cannot create a non-constructed sheet from a constructed sheet"); RefPtr clone = new StyleSheet(*this, aCloneParent, aCloneOwnerRule, aCloneDocumentOrShadowRoot, aCloneOwningNode); return clone.forget(); } +already_AddRefed StyleSheet::CloneAdoptedSheet( + Document& aConstructorDocument) const { + MOZ_ASSERT(IsConstructed(), + "Cannot create a constructed sheet from a non-constructed sheet"); + MOZ_ASSERT(aConstructorDocument.IsStaticDocument(), + "Should never clone adopted sheets for a non-static document"); + RefPtr clone = new StyleSheet(*this, + /* aParentToUse */ nullptr, + /* aOwnerRuleToUse */ nullptr, + /* aDocumentOrShadowRoot */ nullptr, + /* aOwningNodeToUse */ nullptr); + clone->mConstructorDocument = &aConstructorDocument; + return clone.forget(); +} + ServoCSSRuleList* StyleSheet::GetCssRulesInternal() { if (!mRuleList) { EnsureUniqueInner(); diff --git a/layout/style/StyleSheet.h b/layout/style/StyleSheet.h index 05555c6fca5a..a21a00afa59a 100644 --- a/layout/style/StyleSheet.h +++ b/layout/style/StyleSheet.h @@ -221,6 +221,13 @@ class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache { dom::DocumentOrShadowRoot* aCloneDocumentOrShadowRoot, nsINode* aCloneOwningNode) const; + /** + * Creates a clone of the adopted style sheet as though it were constructed + * by aConstructorDocument. This should only be used for printing. + */ + already_AddRefed CloneAdoptedSheet( + dom::Document& aConstructorDocument) const; + bool HasForcedUniqueInner() const { return bool(mState & State::ForcedUniqueInner); }