Bug 1663826 - Keep freezing navigation during window.print() for compat. r=smaug

This broke in bug 1636728 because we started setting the bit in the
cloned docshell rather than the original one.

Behavior in other browsers seems to be a bit all over the place, but for
now keeping our behavior during window.print() seems sane.

Differential Revision: https://phabricator.services.mozilla.com/D90456
This commit is contained in:
Emilio Cobos Álvarez 2020-09-16 22:55:19 +00:00
Родитель df6bc55b1b
Коммит 567d300760
6 изменённых файлов: 58 добавлений и 90 удалений

Просмотреть файл

@ -6117,11 +6117,10 @@ void Document::SetHeaderData(nsAtom* aHeaderField, const nsAString& aData) {
SetPreferredStyleSheetSet(aData);
}
if (aHeaderField == nsGkAtoms::refresh) {
// We get into this code before we have a script global yet, so get to
// our container via mDocumentContainer.
nsCOMPtr<nsIRefreshURI> refresher(mDocumentContainer);
if (refresher) {
if (aHeaderField == nsGkAtoms::refresh && !IsStaticDocument()) {
// We get into this code before we have a script global yet, so get to our
// container via mDocumentContainer.
if (nsCOMPtr<nsIRefreshURI> refresher = mDocumentContainer.get()) {
// Note: using mDocumentURI instead of mBaseURI here, for consistency
// (used to just use the current URI of our webnavigation, but that
// should really be the same thing). Note that this code can run

Просмотреть файл

@ -5232,6 +5232,46 @@ static void DispatchPrintEventToWindowTree(Document& aDoc,
}
}
#ifdef NS_PRINTING
static void SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode,
bool aIsPrintingOrPP,
bool aStartAtTop = true) {
nsCOMPtr<nsIDocShellTreeItem> parentItem(aParentNode);
// find top of "same parent" tree
if (aStartAtTop) {
while (parentItem) {
nsCOMPtr<nsIDocShellTreeItem> parent;
parentItem->GetInProcessSameTypeParent(getter_AddRefs(parent));
if (!parent) {
break;
}
parentItem = parent;
}
}
if (nsCOMPtr<nsIDocShell> viewerContainer = do_QueryInterface(parentItem)) {
viewerContainer->SetIsPrinting(aIsPrintingOrPP);
}
if (!aParentNode) {
return;
}
// Traverse children to see if any of them are printing.
int32_t n;
aParentNode->GetInProcessChildCount(&n);
for (int32_t i = 0; i < n; i++) {
nsCOMPtr<nsIDocShellTreeItem> child;
aParentNode->GetInProcessChildAt(i, getter_AddRefs(child));
NS_ASSERTION(child, "child isn't nsIDocShell");
if (child) {
SetIsPrintingInDocShellTree(child, aIsPrintingOrPP, false);
}
}
}
#endif
void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
if (!AreDialogsEnabled()) {
// We probably want to keep throwing here; silently doing nothing is a bit
@ -5271,6 +5311,11 @@ void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
return;
}
nsCOMPtr<nsIDocShell> docShell = mDocShell;
SetIsPrintingInDocShellTree(docShell, true);
auto unset =
MakeScopeExit([&] { SetIsPrintingInDocShellTree(docShell, false); });
const bool isPreview = StaticPrefs::print_tab_modal_enabled() &&
!StaticPrefs::print_always_print_silent();
if (isPreview) {

Просмотреть файл

@ -401,13 +401,6 @@ class nsDocumentViewer final : public nsIContentViewer,
void InvalidatePotentialSubDocDisplayItem();
#ifdef NS_PRINTING
// Called when the DocViewer is notified that the state
// of Printing or PP has changed
void SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode,
bool aIsPrintingOrPP, bool aStartAtTop);
#endif // NS_PRINTING
// Whether we should attach to the top level widget. This is true if we
// are sharing/recycling a single base widget and not creating multiple
// child widgets.
@ -431,7 +424,6 @@ class nsDocumentViewer final : public nsIContentViewer,
// class, please make the ownership explicit (pinkerton, scc).
WeakPtr<nsDocShell> mContainer; // it owns me!
nsWeakPtr mTopContainerWhilePrinting;
RefPtr<nsDeviceContext> mDeviceContext; // We create and own this baby
// the following six items are explicitly in this order
@ -3588,49 +3580,6 @@ nsDocumentViewer::GetPrintPreviewNumPages(int32_t* aPrintPreviewNumPages) {
//----------------------------------------------------------------------------------
// Walks the document tree and tells each DocShell whether Printing/PP is
// happening
void nsDocumentViewer::SetIsPrintingInDocShellTree(
nsIDocShellTreeItem* aParentNode, bool aIsPrintingOrPP, bool aStartAtTop) {
nsCOMPtr<nsIDocShellTreeItem> parentItem(aParentNode);
// find top of "same parent" tree
if (aStartAtTop) {
if (aIsPrintingOrPP) {
while (parentItem) {
nsCOMPtr<nsIDocShellTreeItem> parent;
parentItem->GetInProcessSameTypeParent(getter_AddRefs(parent));
if (!parent) {
break;
}
parentItem = parent;
}
mTopContainerWhilePrinting = do_GetWeakReference(parentItem);
} else {
parentItem = do_QueryReferent(mTopContainerWhilePrinting);
}
}
// Check to see if the DocShell's ContentViewer is printing/PP
nsCOMPtr<nsIDocShell> viewerContainer = do_QueryInterface(parentItem);
if (viewerContainer) {
viewerContainer->SetIsPrinting(aIsPrintingOrPP);
}
if (!aParentNode) {
return;
}
// Traverse children to see if any of them are printing.
int32_t n;
aParentNode->GetInProcessChildCount(&n);
for (int32_t i = 0; i < n; i++) {
nsCOMPtr<nsIDocShellTreeItem> child;
aParentNode->GetInProcessChildAt(i, getter_AddRefs(child));
NS_ASSERTION(child, "child isn't nsIDocShell");
if (child) {
SetIsPrintingInDocShellTree(child, aIsPrintingOrPP, false);
}
}
}
#endif // NS_PRINTING
bool nsDocumentViewer::ShouldAttachToTopLevel() {
@ -3677,21 +3626,6 @@ bool nsDocumentViewer::GetIsPrinting() const {
return false;
}
//------------------------------------------------------------
// Notification from the PrintJob of the current Printing status
void nsDocumentViewer::SetIsPrinting(bool aIsPrinting) {
#ifdef NS_PRINTING
// Set all the docShells in the docshell tree to be printing.
// that way if anyone of them tries to "navigate" it can't
nsCOMPtr<nsIDocShell> docShell(mContainer);
if (docShell || !aIsPrinting) {
SetIsPrintingInDocShellTree(docShell, aIsPrinting, true);
} else {
NS_WARNING("Did you close a window before printing?");
}
#endif
}
//------------------------------------------------------------
// The PrintJob holds the current value
// this called from inside the DocViewer.
@ -3707,15 +3641,6 @@ bool nsDocumentViewer::GetIsPrintPreview() const {
//------------------------------------------------------------
// Notification from the PrintJob of the current PP status
void nsDocumentViewer::SetIsPrintPreview(bool aIsPrintPreview) {
#ifdef NS_PRINTING
// Set all the docShells in the docshell tree to be printing.
// that way if anyone of them tries to "navigate" it can't
nsCOMPtr<nsIDocShell> docShell(mContainer);
if (docShell || !aIsPrintPreview) {
SetIsPrintingInDocShellTree(docShell, aIsPrintPreview, true);
}
#endif
// Protect against pres shell destruction running scripts.
nsAutoScriptBlocker scriptBlocker;

Просмотреть файл

@ -33,7 +33,6 @@ class nsIDocumentViewerPrint : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_VIEWER_PRINT_IID)
virtual void SetIsPrinting(bool aIsPrinting) = 0;
virtual bool GetIsPrinting() const = 0;
virtual void SetIsPrintPreview(bool aIsPrintPreview) = 0;
@ -62,7 +61,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentViewerPrint,
/* Use this macro when declaring classes that implement this interface. */
#define NS_DECL_NSIDOCUMENTVIEWERPRINT \
void SetIsPrinting(bool aIsPrinting) override; \
bool GetIsPrinting() const override; \
void SetIsPrintPreview(bool aIsPrintPreview) override; \
bool GetIsPrintPreview() const override; \

Просмотреть файл

@ -538,12 +538,10 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview,
// clear mPtrPreview so that code will use mPtr until that happens.
mPrtPreview = nullptr;
// ensures docShell tree navigation in frozen
SetIsPrintPreview(true);
} else {
mProgressDialogIsShown = false;
// ensures docShell tree navigation in frozen
SetIsPrinting(true);
}
@ -2318,11 +2316,6 @@ void nsPrintJob::SetIsPrinting(bool aIsPrinting) {
if (aIsPrinting) {
mHasEverPrinted = true;
}
// Calling SetIsPrinting while in print preview confuses the document viewer
// This is safe because we prevent exiting print preview while printing
if (!mCreatedForPrintPreview && mDocViewerPrint) {
mDocViewerPrint->SetIsPrinting(aIsPrinting);
}
if (mPrt && aIsPrinting) {
mPrt->mPreparingForPrint = true;
}

Просмотреть файл

@ -5,8 +5,16 @@
onload = function() {
// window.print() is special until after the load event is finished firing.
setTimeout(function() {
// This one should block until we're done printing.
// This fires a timer which would trigger a navigation and prevent the
// test from completing if it happens during window.print().
let meta = document.createElement("meta");
meta.setAttribute("http-equiv", "refresh");
meta.setAttribute("content", "0; url=/unlikely-to-be-found");
document.head.appendChild(meta);
// This one should block until we're done printing, and block the
// navigation too.
window.print();
meta.remove();
document.body.insertAdjacentHTML('beforeend', `<div id="after-first-print">After first print</div>`);
let canvas = document.getElementById("canvas");