зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1557983. Significantly simplify and fix the 'beforeprint'/'afterprint' dispatching code.
This fixes two issue. First, the code shouldn't be dispatching these events every time it gets a new Print or PrintPreview call. It only needs to dispatch the events to the original document that we're going to clone from. When cloning from existing static clones any changes made by 'beforeprint' will be present in the existing static clone. Second, the code tries to delay the 'afterprint' event until after mozPrintCallback callbacks have been invoked, but those callbacks are invoked in the cloned document, whereas the events are sent to the original document! So there is no reason to do this. Differential Revision: https://phabricator.services.mozilla.com/D34280
This commit is contained in:
Родитель
c5e2dceec6
Коммит
eee2d4c223
|
@ -149,9 +149,6 @@ static mozilla::LazyLogModule gPrintingLog("printing");
|
||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
|
|
||||||
class nsDocumentViewer;
|
class nsDocumentViewer;
|
||||||
namespace mozilla {
|
|
||||||
class AutoPrintEventDispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
// a small delegate class used to avoid circular references
|
// a small delegate class used to avoid circular references
|
||||||
|
|
||||||
|
@ -467,7 +464,6 @@ class nsDocumentViewer final : public nsIContentViewer,
|
||||||
nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
|
nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
|
||||||
|
|
||||||
RefPtr<nsPrintJob> mPrintJob;
|
RefPtr<nsPrintJob> mPrintJob;
|
||||||
UniquePtr<AutoPrintEventDispatcher> mAutoBeforeAndAfterPrint;
|
|
||||||
# endif // NS_PRINT_PREVIEW
|
# endif // NS_PRINT_PREVIEW
|
||||||
|
|
||||||
#endif // NS_PRINTING
|
#endif // NS_PRINTING
|
||||||
|
@ -481,50 +477,6 @@ class nsDocumentViewer final : public nsIContentViewer,
|
||||||
bool mHidden;
|
bool mHidden;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A RAII class for automatic dispatch of the 'beforeprint' and 'afterprint'
|
|
||||||
* events ('beforeprint' on construction, 'afterprint' on destruction).
|
|
||||||
*
|
|
||||||
* https://developer.mozilla.org/en-US/docs/Web/Events/beforeprint
|
|
||||||
* https://developer.mozilla.org/en-US/docs/Web/Events/afterprint
|
|
||||||
*/
|
|
||||||
class AutoPrintEventDispatcher {
|
|
||||||
public:
|
|
||||||
explicit AutoPrintEventDispatcher(Document* aTop) : mTop(aTop) {
|
|
||||||
DispatchEventToWindowTree(u"beforeprint"_ns);
|
|
||||||
}
|
|
||||||
~AutoPrintEventDispatcher() { DispatchEventToWindowTree(u"afterprint"_ns); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static CallState CollectDocuments(Document& aDoc,
|
|
||||||
nsTArray<nsCOMPtr<Document>>& aDocs) {
|
|
||||||
aDocs.AppendElement(&aDoc);
|
|
||||||
auto recurse = [&aDocs](Document& aSubDoc) {
|
|
||||||
return CollectDocuments(aSubDoc, aDocs);
|
|
||||||
};
|
|
||||||
aDoc.EnumerateSubDocuments(recurse);
|
|
||||||
return CallState::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DispatchEventToWindowTree(const nsAString& aEvent) {
|
|
||||||
nsTArray<nsCOMPtr<Document>> targets;
|
|
||||||
if (mTop) {
|
|
||||||
CollectDocuments(*mTop, targets);
|
|
||||||
}
|
|
||||||
for (nsCOMPtr<Document>& doc : targets) {
|
|
||||||
nsContentUtils::DispatchTrustedEvent(doc, doc->GetWindow(), aEvent,
|
|
||||||
CanBubble::eNo, Cancelable::eNo,
|
|
||||||
nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<Document> mTop;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
class nsDocumentShownDispatcher : public Runnable {
|
class nsDocumentShownDispatcher : public Runnable {
|
||||||
public:
|
public:
|
||||||
explicit nsDocumentShownDispatcher(nsCOMPtr<Document> aDocument)
|
explicit nsDocumentShownDispatcher(nsCOMPtr<Document> aDocument)
|
||||||
|
@ -1660,8 +1612,6 @@ nsDocumentViewer::Destroy() {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Dispatch the 'afterprint' event now, if pending:
|
|
||||||
mAutoBeforeAndAfterPrint = nullptr;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We want to make sure to disconnect mBFCachePreventionObserver before we
|
// We want to make sure to disconnect mBFCachePreventionObserver before we
|
||||||
|
@ -3205,11 +3155,6 @@ nsDocumentViewer::Print(nsIPrintSettings* aPrintSettings,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch 'beforeprint' event and ensure 'afterprint' will be dispatched:
|
|
||||||
MOZ_ASSERT(!mAutoBeforeAndAfterPrint,
|
|
||||||
"We don't want to dispatch nested beforeprint/afterprint");
|
|
||||||
auto autoBeforeAndAfterPrint =
|
|
||||||
MakeUnique<AutoPrintEventDispatcher>(mDocument);
|
|
||||||
NS_ENSURE_STATE(!GetIsPrinting());
|
NS_ENSURE_STATE(!GetIsPrinting());
|
||||||
// If we are hosting a full-page plugin, tell it to print
|
// If we are hosting a full-page plugin, tell it to print
|
||||||
// first. It shows its own native print UI.
|
// first. It shows its own native print UI.
|
||||||
|
@ -3233,11 +3178,6 @@ nsDocumentViewer::Print(nsIPrintSettings* aPrintSettings,
|
||||||
}
|
}
|
||||||
mPrintJob = printJob;
|
mPrintJob = printJob;
|
||||||
}
|
}
|
||||||
if (printJob->HasPrintCallbackCanvas()) {
|
|
||||||
// Postpone the 'afterprint' event until after the mozPrintCallback
|
|
||||||
// callbacks have been called:
|
|
||||||
mAutoBeforeAndAfterPrint = std::move(autoBeforeAndAfterPrint);
|
|
||||||
}
|
|
||||||
rv = printJob->Print(mDocument, aPrintSettings, aWebProgressListener);
|
rv = printJob->Print(mDocument, aPrintSettings, aWebProgressListener);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
OnDonePrinting();
|
OnDonePrinting();
|
||||||
|
@ -3273,18 +3213,6 @@ nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings,
|
||||||
nsCOMPtr<Document> doc = window->GetDoc();
|
nsCOMPtr<Document> doc = window->GetDoc();
|
||||||
NS_ENSURE_STATE(doc);
|
NS_ENSURE_STATE(doc);
|
||||||
|
|
||||||
// Dispatch 'beforeprint' event and ensure 'afterprint' will be dispatched:
|
|
||||||
// XXX Currently[1] when the user switches between portrait and landscape
|
|
||||||
// mode in print preview, we re-enter this function before
|
|
||||||
// mAutoBeforeAndAfterPrint (if set) is cleared to dispatch the 'afterprint'
|
|
||||||
// event. To avoid sending multiple 'beforeprint'/'afterprint' events we
|
|
||||||
// must avoid creating a new AutoPrintEventDispatcher object here if we
|
|
||||||
// already have one saved in mAutoBeforeAndAfterPrint.
|
|
||||||
// [1] Until PDF.js is removed (though, maybe after that as well).
|
|
||||||
UniquePtr<AutoPrintEventDispatcher> autoBeforeAndAfterPrint;
|
|
||||||
if (!mAutoBeforeAndAfterPrint) {
|
|
||||||
autoBeforeAndAfterPrint = MakeUnique<AutoPrintEventDispatcher>(doc);
|
|
||||||
}
|
|
||||||
NS_ENSURE_STATE(!GetIsPrinting());
|
NS_ENSURE_STATE(!GetIsPrinting());
|
||||||
// beforeprint event may have caused ContentViewer to be shutdown.
|
// beforeprint event may have caused ContentViewer to be shutdown.
|
||||||
NS_ENSURE_STATE(mContainer);
|
NS_ENSURE_STATE(mContainer);
|
||||||
|
@ -3308,11 +3236,6 @@ nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings,
|
||||||
|
|
||||||
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_PREVIEW_OPENED, 1);
|
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_PREVIEW_OPENED, 1);
|
||||||
}
|
}
|
||||||
if (autoBeforeAndAfterPrint && printJob->HasPrintCallbackCanvas()) {
|
|
||||||
// Postpone the 'afterprint' event until after the mozPrintCallback
|
|
||||||
// callbacks have been called:
|
|
||||||
mAutoBeforeAndAfterPrint = std::move(autoBeforeAndAfterPrint);
|
|
||||||
}
|
|
||||||
rv = printJob->PrintPreview(doc, aPrintSettings, aWebProgressListener);
|
rv = printJob->PrintPreview(doc, aPrintSettings, aWebProgressListener);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
OnDonePrinting();
|
OnDonePrinting();
|
||||||
|
@ -3647,11 +3570,6 @@ void nsDocumentViewer::SetIsPrinting(bool aIsPrinting) {
|
||||||
} else {
|
} else {
|
||||||
NS_WARNING("Did you close a window before printing?");
|
NS_WARNING("Did you close a window before printing?");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aIsPrinting) {
|
|
||||||
// Dispatch the 'afterprint' event now, if pending:
|
|
||||||
mAutoBeforeAndAfterPrint = nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3678,10 +3596,6 @@ void nsDocumentViewer::SetIsPrintPreview(bool aIsPrintPreview) {
|
||||||
if (docShell || !aIsPrintPreview) {
|
if (docShell || !aIsPrintPreview) {
|
||||||
SetIsPrintingInDocShellTree(docShell, aIsPrintPreview, true);
|
SetIsPrintingInDocShellTree(docShell, aIsPrintPreview, true);
|
||||||
}
|
}
|
||||||
if (!aIsPrintPreview) {
|
|
||||||
// Dispatch the 'afterprint' event now, if pending:
|
|
||||||
mAutoBeforeAndAfterPrint = nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Protect against pres shell destruction running scripts.
|
// Protect against pres shell destruction running scripts.
|
||||||
|
|
|
@ -168,6 +168,26 @@ static void DumpPrintObjectsTreeLayout(const UniquePtr<nsPrintObject>& aPO,
|
||||||
# define DUMP_DOC_TREELAYOUT
|
# define DUMP_DOC_TREELAYOUT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static CallState CollectDocuments(Document& aDoc,
|
||||||
|
nsTArray<nsCOMPtr<Document>>& aDocs) {
|
||||||
|
aDocs.AppendElement(&aDoc);
|
||||||
|
auto recurse = [&aDocs](Document& aSubDoc) {
|
||||||
|
return CollectDocuments(aSubDoc, aDocs);
|
||||||
|
};
|
||||||
|
aDoc.EnumerateSubDocuments(recurse);
|
||||||
|
return CallState::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DispatchEventToWindowTree(Document& aDoc, const nsAString& aEvent) {
|
||||||
|
nsTArray<nsCOMPtr<Document>> targets;
|
||||||
|
CollectDocuments(aDoc, targets);
|
||||||
|
for (nsCOMPtr<Document>& doc : targets) {
|
||||||
|
nsContentUtils::DispatchTrustedEvent(doc, doc->GetWindow(), aEvent,
|
||||||
|
CanBubble::eNo, Cancelable::eNo,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class nsScriptSuppressor {
|
class nsScriptSuppressor {
|
||||||
public:
|
public:
|
||||||
explicit nsScriptSuppressor(nsPrintJob* aPrintJob)
|
explicit nsScriptSuppressor(nsPrintJob* aPrintJob)
|
||||||
|
@ -663,6 +683,14 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview,
|
||||||
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell, &rv));
|
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell, &rv));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (!aSourceDoc->IsStaticDocument()) {
|
||||||
|
// This is the original document. We must send 'beforeprint' and
|
||||||
|
// 'afterprint' events to give the document the chance to make changes
|
||||||
|
// for print output. (Obviously if `aSourceDoc` is a clone, it already
|
||||||
|
// has these changes.)
|
||||||
|
DispatchEventToWindowTree(*aSourceDoc, u"beforeprint"_ns);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
nsAutoScriptBlocker scriptBlocker;
|
nsAutoScriptBlocker scriptBlocker;
|
||||||
printData->mPrintObject = MakeUnique<nsPrintObject>();
|
printData->mPrintObject = MakeUnique<nsPrintObject>();
|
||||||
|
@ -680,6 +708,10 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview,
|
||||||
printData->mPrintObject, &printData->mPrintDocList);
|
printData->mPrintObject, &printData->mPrintDocList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!aSourceDoc->IsStaticDocument()) {
|
||||||
|
DispatchEventToWindowTree(*aSourceDoc, u"afterprint"_ns);
|
||||||
|
}
|
||||||
|
|
||||||
// The nsAutoScriptBlocker above will now have been destroyed, which may
|
// The nsAutoScriptBlocker above will now have been destroyed, which may
|
||||||
// cause our print/print-preview operation to finish. In this case, we
|
// cause our print/print-preview operation to finish. In this case, we
|
||||||
// should immediately return an error code so that the root caller knows
|
// should immediately return an error code so that the root caller knows
|
||||||
|
|
Загрузка…
Ссылка в новой задаче