Backed out 3 changesets (bug 1875481) for basicWindowDotPrintTest related junit failures.

Backed out changeset cd024cb2768e (bug 1875481)
Backed out changeset 6b7be15cd017 (bug 1875481)
Backed out changeset d1da53c0673b (bug 1875481)
This commit is contained in:
Stanca Serban 2024-04-09 05:56:47 +03:00
parent f268233fbd
commit 9879879814
28 changed files with 78 additions and 1583 deletions

View File

@ -300,10 +300,10 @@ export const ContentAnalysis = {
);
return;
}
const analysisType = request.analysisType;
const operation = request.analysisType;
// For operations that block browser interaction, show the "slow content analysis"
// dialog faster
let slowTimeoutMs = this._shouldShowBlockingNotification(analysisType)
let slowTimeoutMs = this._shouldShowBlockingNotification(operation)
? this._SLOW_DLP_NOTIFICATION_BLOCKING_TIMEOUT_MS
: this._SLOW_DLP_NOTIFICATION_NONBLOCKING_TIMEOUT_MS;
let browsingContext = request.windowGlobalParent?.browsingContext;
@ -333,7 +333,7 @@ export const ContentAnalysis = {
timer: lazy.setTimeout(() => {
this.dlpBusyViewsByTopBrowsingContext.setEntry(browsingContext, {
notification: this._showSlowCAMessage(
analysisType,
operation,
request,
resourceNameOrOperationType,
browsingContext
@ -450,10 +450,7 @@ export const ContentAnalysis = {
}
if (this._SHOW_NOTIFICATIONS) {
let topWindow =
aBrowsingContext.topChromeWindow ??
aBrowsingContext.embedderWindowGlobal.browsingContext.topChromeWindow;
const notification = new topWindow.Notification(
const notification = new aBrowsingContext.topChromeWindow.Notification(
this.l10n.formatValueSync("contentanalysis-notification-title"),
{
body: aMessage,
@ -472,10 +469,10 @@ export const ContentAnalysis = {
return null;
},
_shouldShowBlockingNotification(aAnalysisType) {
_shouldShowBlockingNotification(aOperation) {
return !(
aAnalysisType == Ci.nsIContentAnalysisRequest.eFileDownloaded ||
aAnalysisType == Ci.nsIContentAnalysisRequest.ePrint
aOperation == Ci.nsIContentAnalysisRequest.eFileDownloaded ||
aOperation == Ci.nsIContentAnalysisRequest.ePrint
);
},
@ -491,9 +488,6 @@ export const ContentAnalysis = {
case Ci.nsIContentAnalysisRequest.eDroppedText:
l10nId = "contentanalysis-operationtype-dropped-text";
break;
case Ci.nsIContentAnalysisRequest.eOperationPrint:
l10nId = "contentanalysis-operationtype-print";
break;
}
if (!l10nId) {
console.error(
@ -602,14 +596,10 @@ export const ContentAnalysis = {
case Ci.nsIContentAnalysisRequest.eDroppedText:
l10nId = "contentanalysis-slow-agent-dialog-body-dropped-text";
break;
case Ci.nsIContentAnalysisRequest.eOperationPrint:
l10nId = "contentanalysis-slow-agent-dialog-body-print";
break;
}
if (!l10nId) {
console.error(
"Unknown operationTypeForDisplay: ",
aResourceNameOrOperationType
"Unknown operationTypeForDisplay: " + aResourceNameOrOperationType
);
return "";
}

View File

@ -6,10 +6,8 @@
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "ContentAnalysis.h"
#include "ErrorList.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Components.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/EventForwards.h"
#include "mozilla/AsyncEventDispatcher.h"
@ -49,7 +47,6 @@
#include "nsFrameLoader.h"
#include "nsFrameLoaderOwner.h"
#include "nsGlobalWindowOuter.h"
#include "nsIContentAnalysis.h"
#include "nsIWebBrowserChrome.h"
#include "nsIXULRuntime.h"
#include "nsNetUtil.h"
@ -671,9 +668,6 @@ CanonicalBrowsingContext::ReplaceLoadingSessionHistoryEntryForLoad(
using PrintPromise = CanonicalBrowsingContext::PrintPromise;
#ifdef NS_PRINTING
// Clients must call StaticCloneForPrintingCreated or
// NoStaticCloneForPrintingWillBeCreated before the underlying promise can
// resolve.
class PrintListenerAdapter final : public nsIWebProgressListener {
public:
explicit PrintListenerAdapter(PrintPromise::Private* aPromise)
@ -684,14 +678,10 @@ class PrintListenerAdapter final : public nsIWebProgressListener {
// NS_DECL_NSIWEBPROGRESSLISTENER
NS_IMETHOD OnStateChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aStatus) override {
MOZ_ASSERT(NS_IsMainThread());
if (aStateFlags & nsIWebProgressListener::STATE_STOP &&
aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT && mPromise) {
mPrintJobFinished = true;
if (mHaveSetBrowsingContext) {
mPromise->Resolve(mClonedStaticBrowsingContext, __func__);
mPromise = nullptr;
}
mPromise->Resolve(true, __func__);
mPromise = nullptr;
}
return NS_OK;
}
@ -726,28 +716,10 @@ class PrintListenerAdapter final : public nsIWebProgressListener {
return NS_OK;
}
void StaticCloneForPrintingCreated(
MaybeDiscardedBrowsingContext&& aClonedStaticBrowsingContext) {
MOZ_ASSERT(NS_IsMainThread());
mClonedStaticBrowsingContext = std::move(aClonedStaticBrowsingContext);
mHaveSetBrowsingContext = true;
if (mPrintJobFinished && mPromise) {
mPromise->Resolve(mClonedStaticBrowsingContext, __func__);
mPromise = nullptr;
}
}
void NoStaticCloneForPrintingWillBeCreated() {
StaticCloneForPrintingCreated(nullptr);
}
private:
~PrintListenerAdapter() = default;
RefPtr<PrintPromise::Private> mPromise;
MaybeDiscardedBrowsingContext mClonedStaticBrowsingContext = nullptr;
bool mHaveSetBrowsingContext = false;
bool mPrintJobFinished = false;
};
NS_IMPL_ISUPPORTS(PrintListenerAdapter, nsIWebProgressListener)
@ -763,9 +735,7 @@ already_AddRefed<Promise> CanonicalBrowsingContext::PrintJS(
Print(aPrintSettings)
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise](MaybeDiscardedBrowsingContext) {
promise->MaybeResolveWithUndefined();
},
[promise](bool) { promise->MaybeResolveWithUndefined(); },
[promise](nsresult aResult) { promise->MaybeReject(aResult); });
return promise.forget();
}
@ -775,72 +745,7 @@ RefPtr<PrintPromise> CanonicalBrowsingContext::Print(
#ifndef NS_PRINTING
return PrintPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
#else
// Content analysis is not supported on non-Windows platforms.
# if defined(XP_WIN)
bool needContentAnalysis = false;
nsCOMPtr<nsIContentAnalysis> contentAnalysis =
mozilla::components::nsIContentAnalysis::Service();
Unused << NS_WARN_IF(!contentAnalysis);
if (contentAnalysis) {
nsresult rv = contentAnalysis->GetIsActive(&needContentAnalysis);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
if (needContentAnalysis) {
auto done = MakeRefPtr<PrintPromise::Private>(__func__);
contentanalysis::ContentAnalysis::PrintToPDFToDetermineIfPrintAllowed(
this, aPrintSettings)
->Then(
GetCurrentSerialEventTarget(), __func__,
[done, aPrintSettings = RefPtr{aPrintSettings},
self = RefPtr{this}](
contentanalysis::ContentAnalysis::PrintAllowedResult aResponse)
MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA mutable {
if (aResponse.mAllowed) {
self->PrintWithNoContentAnalysis(
aPrintSettings, false,
aResponse.mCachedStaticDocumentBrowsingContext)
->ChainTo(done.forget(), __func__);
} else {
// Since we are not doing the second print in this case,
// release the clone that is no longer needed.
self->ReleaseClonedPrint(
aResponse.mCachedStaticDocumentBrowsingContext);
done->Reject(NS_ERROR_CONTENT_BLOCKED, __func__);
}
},
[done, self = RefPtr{this}](
contentanalysis::ContentAnalysis::PrintAllowedError
aErrorResponse) MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA {
// Since we are not doing the second print in this case, release
// the clone that is no longer needed.
self->ReleaseClonedPrint(
aErrorResponse.mCachedStaticDocumentBrowsingContext);
done->Reject(aErrorResponse.mError, __func__);
});
return done;
}
# endif
return PrintWithNoContentAnalysis(aPrintSettings, false, nullptr);
#endif
}
void CanonicalBrowsingContext::ReleaseClonedPrint(
const MaybeDiscardedBrowsingContext& aClonedStaticBrowsingContext) {
#ifdef NS_PRINTING
auto* browserParent = GetBrowserParent();
if (NS_WARN_IF(!browserParent)) {
return;
}
Unused << browserParent->SendDestroyPrintClone(aClonedStaticBrowsingContext);
#endif
}
RefPtr<PrintPromise> CanonicalBrowsingContext::PrintWithNoContentAnalysis(
nsIPrintSettings* aPrintSettings, bool aForceStaticDocument,
const MaybeDiscardedBrowsingContext& aCachedStaticDocument) {
#ifndef NS_PRINTING
return PrintPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
#else
auto promise = MakeRefPtr<PrintPromise::Private>(__func__);
auto listener = MakeRefPtr<PrintListenerAdapter>(promise);
if (IsInProcess()) {
@ -852,14 +757,12 @@ RefPtr<PrintPromise> CanonicalBrowsingContext::PrintWithNoContentAnalysis(
}
ErrorResult rv;
listener->NoStaticCloneForPrintingWillBeCreated();
outerWindow->Print(aPrintSettings,
/* aRemotePrintJob = */ nullptr, listener,
/* aDocShellToCloneInto = */ nullptr,
nsGlobalWindowOuter::IsPreview::No,
nsGlobalWindowOuter::IsForWindowDotPrint::No,
/* aPrintPreviewCallback = */ nullptr,
/* aCachedBrowsingContext = */ nullptr, rv);
/* aPrintPreviewCallback = */ nullptr, rv);
if (rv.Failed()) {
promise->Reject(rv.StealNSResult(), __func__);
}
@ -902,31 +805,12 @@ RefPtr<PrintPromise> CanonicalBrowsingContext::PrintWithNoContentAnalysis(
printData.remotePrintJob() =
browserParent->Manager()->SendPRemotePrintJobConstructor(remotePrintJob);
remotePrintJob->RegisterListener(listener);
if (listener) {
remotePrintJob->RegisterListener(listener);
}
if (!aCachedStaticDocument.IsNullOrDiscarded()) {
// There is no cloned static browsing context that
// SendPrintClonedPage() will return, so indicate this
// so listener can resolve its promise.
listener->NoStaticCloneForPrintingWillBeCreated();
if (NS_WARN_IF(!browserParent->SendPrintClonedPage(
this, printData, aCachedStaticDocument))) {
promise->Reject(NS_ERROR_FAILURE, __func__);
}
} else {
RefPtr<PBrowserParent::PrintPromise> printPromise =
browserParent->SendPrint(this, printData, aForceStaticDocument);
printPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[listener](MaybeDiscardedBrowsingContext cachedStaticDocument) {
// promise will get resolved by the listener
listener->StaticCloneForPrintingCreated(
std::move(cachedStaticDocument));
},
[promise](ResponseRejectReason reason) {
NS_WARNING("SendPrint() failed");
promise->Reject(NS_ERROR_FAILURE, __func__);
});
if (NS_WARN_IF(!browserParent->SendPrint(this, printData))) {
promise->Reject(NS_ERROR_FAILURE, __func__);
}
return promise.forget();
#endif

View File

@ -136,16 +136,11 @@ class CanonicalBrowsingContext final : public BrowsingContext {
UniquePtr<LoadingSessionHistoryInfo> ReplaceLoadingSessionHistoryEntryForLoad(
LoadingSessionHistoryInfo* aInfo, nsIChannel* aNewChannel);
using PrintPromise =
MozPromise<MaybeDiscardedBrowsingContext, nsresult, false>;
using PrintPromise = MozPromise</* unused */ bool, nsresult, false>;
MOZ_CAN_RUN_SCRIPT RefPtr<PrintPromise> Print(nsIPrintSettings*);
MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> PrintJS(nsIPrintSettings*,
ErrorResult&);
MOZ_CAN_RUN_SCRIPT RefPtr<PrintPromise> PrintWithNoContentAnalysis(
nsIPrintSettings* aPrintSettings, bool aForceStaticDocument,
const MaybeDiscardedBrowsingContext& aClonedStaticBrowsingContext);
MOZ_CAN_RUN_SCRIPT void ReleaseClonedPrint(
const MaybeDiscardedBrowsingContext& aClonedStaticBrowsingContext);
// Call the given callback on all top-level descendant BrowsingContexts.
// Return Callstate::Stop from the callback to stop calling further children.
//

View File

@ -3388,8 +3388,7 @@ already_AddRefed<Promise> nsFrameLoader::PrintPreview(
/* aListener = */ nullptr, docShellToCloneInto,
nsGlobalWindowOuter::IsPreview::Yes,
nsGlobalWindowOuter::IsForWindowDotPrint::No,
[resolve](const PrintPreviewResultInfo& aInfo) { resolve(aInfo); },
nullptr, rv);
[resolve](const PrintPreviewResultInfo& aInfo) { resolve(aInfo); }, rv);
if (NS_WARN_IF(rv.Failed())) {
promise->MaybeReject(std::move(rv));
}

View File

@ -3752,7 +3752,7 @@ Nullable<WindowProxyHolder> nsGlobalWindowInner::PrintPreview(
/* aRemotePrintJob = */ nullptr, aListener, aDocShellToCloneInto,
nsGlobalWindowOuter::IsPreview::Yes,
nsGlobalWindowOuter::IsForWindowDotPrint::No,
/* aPrintPreviewCallback = */ nullptr, nullptr, aError),
/* aPrintPreviewCallback = */ nullptr, aError),
aError, nullptr);
}

View File

@ -5006,7 +5006,7 @@ void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
const bool forPreview = !StaticPrefs::print_always_print_silent();
Print(nullptr, nullptr, nullptr, nullptr, IsPreview(forPreview),
IsForWindowDotPrint::Yes, nullptr, nullptr, aError);
IsForWindowDotPrint::Yes, nullptr, aError);
#endif
}
@ -5028,8 +5028,7 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
nsIPrintSettings* aPrintSettings, RemotePrintJobChild* aRemotePrintJob,
nsIWebProgressListener* aListener, nsIDocShell* aDocShellToCloneInto,
IsPreview aIsPreview, IsForWindowDotPrint aForWindowDotPrint,
PrintPreviewResolver&& aPrintPreviewCallback,
RefPtr<BrowsingContext>* aCachedBrowsingContext, ErrorResult& aError) {
PrintPreviewResolver&& aPrintPreviewCallback, ErrorResult& aError) {
#ifdef NS_PRINTING
nsCOMPtr<nsIPrintSettingsService> printSettingsService =
do_GetService("@mozilla.org/gfx/printsettings-service;1");
@ -5065,36 +5064,16 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
nsCOMPtr<nsIDocumentViewer> viewer;
RefPtr<BrowsingContext> bc;
bool hasPrintCallbacks = false;
bool wasStaticDocument = docToPrint->IsStaticDocument();
bool usingCachedBrowsingContext = false;
if (aCachedBrowsingContext && *aCachedBrowsingContext) {
MOZ_ASSERT(!wasStaticDocument,
"Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?");
if (!wasStaticDocument) {
// The passed in document is not a static clone and the caller passed in a
// static clone to reuse, so swap it in.
docToPrint = (*aCachedBrowsingContext)->GetDocument();
MOZ_ASSERT(docToPrint);
MOZ_ASSERT(docToPrint->IsStaticDocument());
wasStaticDocument = true;
usingCachedBrowsingContext = true;
}
}
if (wasStaticDocument) {
if (docToPrint->IsStaticDocument()) {
if (aForWindowDotPrint == IsForWindowDotPrint::Yes) {
aError.ThrowNotSupportedError(
"Calling print() from a print preview is unsupported, did you intend "
"to call printPreview() instead?");
return nullptr;
}
if (usingCachedBrowsingContext) {
bc = docToPrint->GetBrowsingContext();
} else {
// We're already a print preview window, just reuse our browsing context /
// content viewer.
bc = sourceBC;
}
// We're already a print preview window, just reuse our browsing context /
// content viewer.
bc = sourceBC;
nsCOMPtr<nsIDocShell> docShell = bc->GetDocShell();
if (!docShell) {
aError.ThrowNotSupportedError("No docshell");
@ -5136,10 +5115,6 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
if (NS_WARN_IF(aError.Failed())) {
return nullptr;
}
if (aCachedBrowsingContext) {
MOZ_ASSERT(!*aCachedBrowsingContext);
*aCachedBrowsingContext = bc;
}
}
if (!bc) {
aError.ThrowNotAllowedError("No browsing context");
@ -5195,24 +5170,6 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
"Content viewer didn't implement nsIWebBrowserPrint");
return nullptr;
}
bool closeWindowAfterPrint;
if (wasStaticDocument) {
// Here the document was a static clone to begin with that this code did not
// create, so we should not clean it up.
// The exception is if we're using the passed-in aCachedBrowsingContext, in
// which case this is the second print with this static document clone that
// we created the first time through, and we are responsible for cleaning it
// up.
closeWindowAfterPrint = usingCachedBrowsingContext;
} else {
// In this case the document was not a static clone, so we made a static
// clone for printing purposes and must clean it up after the print is done.
// The exception is if aCachedBrowsingContext is non-NULL, meaning the
// caller is intending to print this document again, so we need to defer the
// cleanup until after the second print.
closeWindowAfterPrint = !aCachedBrowsingContext;
}
webBrowserPrint->SetCloseWindowAfterPrint(closeWindowAfterPrint);
// For window.print(), we postpone making these calls until the round-trip to
// the parent process (triggered by the OpenInternal call above) calls us

View File

@ -580,8 +580,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
Print(nsIPrintSettings*,
mozilla::layout::RemotePrintJobChild* aRemotePrintJob,
nsIWebProgressListener*, nsIDocShell*, IsPreview, IsForWindowDotPrint,
PrintPreviewResolver&&, RefPtr<mozilla::dom::BrowsingContext>*,
mozilla::ErrorResult&);
PrintPreviewResolver&&, mozilla::ErrorResult&);
mozilla::dom::Selection* GetSelectionOuter();
already_AddRefed<mozilla::dom::Selection> GetSelection() override;
nsScreen* GetScreen();

View File

@ -2342,7 +2342,7 @@ mozilla::ipc::IPCResult BrowserChild::RecvPrintPreview(
/* aListener = */ nullptr, docShellToCloneInto,
nsGlobalWindowOuter::IsPreview::Yes,
nsGlobalWindowOuter::IsForWindowDotPrint::No,
std::move(aCallback), nullptr, IgnoreErrors());
std::move(aCallback), IgnoreErrors());
#endif
return IPC_OK();
}
@ -2359,9 +2359,8 @@ mozilla::ipc::IPCResult BrowserChild::RecvExitPrintPreview() {
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::CommonPrint(
const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData,
RefPtr<BrowsingContext>* aCachedBrowsingContext) {
mozilla::ipc::IPCResult BrowserChild::RecvPrint(
const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData) {
#ifdef NS_PRINTING
if (NS_WARN_IF(aBc.IsNullOrDiscarded())) {
return IPC_OK();
@ -2390,12 +2389,12 @@ mozilla::ipc::IPCResult BrowserChild::CommonPrint(
IgnoredErrorResult rv;
RefPtr printJob = static_cast<RemotePrintJobChild*>(
aPrintData.remotePrintJob().AsChild());
outerWindow->Print(
printSettings, printJob,
/* aListener = */ nullptr,
/* aWindowToCloneInto = */ nullptr, nsGlobalWindowOuter::IsPreview::No,
nsGlobalWindowOuter::IsForWindowDotPrint::No,
/* aPrintPreviewCallback = */ nullptr, aCachedBrowsingContext, rv);
outerWindow->Print(printSettings, printJob,
/* aListener = */ nullptr,
/* aWindowToCloneInto = */ nullptr,
nsGlobalWindowOuter::IsPreview::No,
nsGlobalWindowOuter::IsForWindowDotPrint::No,
/* aPrintPreviewCallback = */ nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
return IPC_OK();
}
@ -2404,49 +2403,6 @@ mozilla::ipc::IPCResult BrowserChild::CommonPrint(
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvPrint(
const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData,
bool aReturnStaticClone, PrintResolver&& aResolve) {
#ifdef NS_PRINTING
RefPtr<BrowsingContext> browsingContext;
auto result = CommonPrint(aBc, aPrintData,
aReturnStaticClone ? &browsingContext : nullptr);
aResolve(browsingContext);
return result;
#else
aResolve(nullptr);
return IPC_OK();
#endif
}
mozilla::ipc::IPCResult BrowserChild::RecvPrintClonedPage(
const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData,
const MaybeDiscardedBrowsingContext& aClonedBc) {
#ifdef NS_PRINTING
if (aClonedBc.IsNullOrDiscarded()) {
return IPC_OK();
}
RefPtr<BrowsingContext> clonedBc = aClonedBc.get();
return CommonPrint(aBc, aPrintData, &clonedBc);
#else
return IPC_OK();
#endif
}
mozilla::ipc::IPCResult BrowserChild::RecvDestroyPrintClone(
const MaybeDiscardedBrowsingContext& aCachedPage) {
#ifdef NS_PRINTING
if (aCachedPage) {
RefPtr<nsPIDOMWindowOuter> window = aCachedPage->GetDOMWindow();
if (NS_WARN_IF(!window)) {
return IPC_OK();
}
window->Close();
}
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvUpdateNativeWindowHandle(
const uintptr_t& aNewHandle) {
#if defined(XP_WIN) && defined(ACCESSIBILITY)

View File

@ -507,15 +507,7 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
mozilla::ipc::IPCResult RecvExitPrintPreview();
MOZ_CAN_RUN_SCRIPT_BOUNDARY mozilla::ipc::IPCResult RecvPrint(
const MaybeDiscardedBrowsingContext&, const PrintData&, bool,
PrintResolver&&);
MOZ_CAN_RUN_SCRIPT_BOUNDARY mozilla::ipc::IPCResult RecvPrintClonedPage(
const MaybeDiscardedBrowsingContext&, const PrintData&,
const MaybeDiscardedBrowsingContext&);
mozilla::ipc::IPCResult RecvDestroyPrintClone(
const MaybeDiscardedBrowsingContext&);
const MaybeDiscardedBrowsingContext&, const PrintData&);
mozilla::ipc::IPCResult RecvUpdateNativeWindowHandle(
const uintptr_t& aNewHandle);
@ -720,11 +712,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
void InternalSetDocShellIsActive(bool aIsActive);
MOZ_CAN_RUN_SCRIPT
mozilla::ipc::IPCResult CommonPrint(
const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData,
RefPtr<BrowsingContext>* aCachedBrowsingContext);
bool CreateRemoteLayerManager(
mozilla::layers::PCompositorBridgeChild* aCompositorChild);

View File

@ -960,33 +960,8 @@ child:
*
* @param aBrowsingContext the browsing context to print.
* @param aPrintData the serialized settings to print with
* @param aReturnStaticClone If the document in aBrowsingContext is not a static clone, whether
* to return the static document clone created.
* Note that if you call this with true but do not later call PrintClonedPage(),
* you must call DestroyPrintCache() to avoid leaks.
*/
async Print(MaybeDiscardedBrowsingContext aBC, PrintData aPrintData, bool aReturnStaticClone) returns(MaybeDiscardedBrowsingContext staticCloneBrowsingContext);
/**
* Tell the child to print the passed in static clone browsing context with the given settings.
*
* @param aBrowsingContext the browsing context to print.
* @param aPrintData the serialized settings to print with
* @param aStaticCloneBrowsingContext The static clone of aBrowsingContext that
* was created by an earlier call to Print(). This is the page that will actually be
* printed.
*/
async PrintClonedPage(MaybeDiscardedBrowsingContext aBC, PrintData aPrintData, MaybeDiscardedBrowsingContext aStaticCloneBrowsingContext);
/**
* Destroy the static document clone for printing, if present. See Print() for details.
* For callers' simplicity, it is safe to call this method even if aStaticCloneBrowsingContext
* is null or has already been discarded.
*
* @param aStaticCloneBrowsingContext The static clone that was created by
* an earlier call to Print().
*/
async DestroyPrintClone(MaybeDiscardedBrowsingContext aStaticCloneBrowsingContext);
async Print(MaybeDiscardedBrowsingContext aBC, PrintData aPrintData);
/**
* Update the child with the tab's current top-level native window handle.

View File

@ -20,6 +20,14 @@
#include "mozilla/dom/TransformerBinding.h"
#include "nsWrapperCache.h"
// XXX: GCC somehow does not allow attributes before lambda return types, while
// clang requires so. See also bug 1627007.
#ifdef __clang__
# define MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA MOZ_CAN_RUN_SCRIPT_BOUNDARY
#else
# define MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA
#endif
namespace mozilla::dom {
using namespace streams_abstract;

View File

@ -449,7 +449,6 @@ class nsDocumentViewer final : public nsIDocumentViewer,
#ifdef NS_PRINTING
unsigned mClosingWhilePrinting : 1;
unsigned mCloseWindowAfterPrint : 1;
# if NS_PRINT_PREVIEW
RefPtr<nsPrintJob> mPrintJob;
@ -521,7 +520,6 @@ nsDocumentViewer::nsDocumentViewer()
mInPermitUnloadPrompt(false),
#ifdef NS_PRINTING
mClosingWhilePrinting(false),
mCloseWindowAfterPrint(false),
#endif // NS_PRINTING
mReloadEncodingSource(kCharsetUninitialized),
mReloadEncoding(nullptr),
@ -3141,20 +3139,6 @@ nsDocumentViewer::GetDoingPrintPreview(bool* aDoingPrintPreview) {
return NS_OK;
}
NS_IMETHODIMP
nsDocumentViewer::GetCloseWindowAfterPrint(bool* aCloseWindowAfterPrint) {
NS_ENSURE_ARG_POINTER(aCloseWindowAfterPrint);
*aCloseWindowAfterPrint = mCloseWindowAfterPrint;
return NS_OK;
}
NS_IMETHODIMP
nsDocumentViewer::SetCloseWindowAfterPrint(bool aCloseWindowAfterPrint) {
mCloseWindowAfterPrint = aCloseWindowAfterPrint;
return NS_OK;
}
NS_IMETHODIMP
nsDocumentViewer::ExitPrintPreview() {
NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
@ -3319,15 +3303,13 @@ void nsDocumentViewer::OnDonePrinting() {
// We are done printing, now clean up.
//
// If the original document to print was not a static clone, we opened a new
// window and are responsible for cleaning up the whole <browser> or window
// (see the OPEN_PRINT_BROWSER code, specifically
// handleStaticCloneCreatedForPrint()), so gotta run window.close(), which
// will take care of this.
// For non-print-preview jobs, we are actually responsible for cleaning up
// our whole <browser> or window (see the OPEN_PRINT_BROWSER code), so gotta
// run window.close(), which will take care of this.
//
// Otherwise the front-end code is responsible for cleaning the UI.
bool closeWindowAfterPrint = GetCloseWindowAfterPrint();
if (closeWindowAfterPrint) {
// For print preview jobs the front-end code is responsible for cleaning the
// UI.
if (!printJob->CreatedForPrintPreview()) {
if (mContainer) {
if (nsCOMPtr<nsPIDOMWindowOuter> win = mContainer->GetWindow()) {
win->Close();

View File

@ -1031,12 +1031,4 @@
# define MOZ_EMPTY_BASES
#endif
// XXX: GCC somehow does not allow attributes before lambda return types, while
// clang requires so. See also bug 1627007.
#ifdef __clang__
# define MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA MOZ_CAN_RUN_SCRIPT_BOUNDARY
#else
# define MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA
#endif
#endif /* mozilla_Attributes_h */

View File

@ -30,7 +30,7 @@ native PrintPreviewResolver(std::function<void(const mozilla::dom::PrintPreviewR
* nsIWebBrowserPrint corresponds to the main interface
* for printing an embedded Gecko web browser window/document
*/
[scriptable, builtinclass, uuid(c9a934ed-fff1-4971-bfba-6c25ad70e1e6)]
[scriptable, uuid(c9a934ed-fff1-4971-bfba-6c25ad70e1e6)]
interface nsIWebBrowserPrint : nsISupports
{
/**
@ -85,13 +85,6 @@ interface nsIWebBrowserPrint : nsISupports
*/
readonly attribute long printPreviewCurrentPageNumber;
/*
* Whether the document to print needs to have its window closed after printing
* is done - see OPEN_PRINT_BROWSER and specifically handleStaticCloneCreatedForPrint().
* This is set if the document is not a static clone.
*/
[infallible] attribute boolean closeWindowAfterPrint;
/**
* Print the specified DOM window
*

View File

@ -11,7 +11,6 @@
#include "base/process_util.h"
#include "GMPUtils.h" // ToHexString
#include "mozilla/Components.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/Logging.h"
@ -25,9 +24,6 @@
#include "nsIFile.h"
#include "nsIGlobalObject.h"
#include "nsIObserverService.h"
#include "nsIOutputStream.h"
#include "nsIPrintSettings.h"
#include "nsIStorageStream.h"
#include "ScopedNSSTypes.h"
#include "xpcpublic.h"
@ -39,7 +35,6 @@
# include <windows.h>
# define SECURITY_WIN32 1
# include <security.h>
# include "mozilla/NativeNt.h"
# include "mozilla/WinDllServices.h"
#endif // XP_WIN
@ -119,11 +114,6 @@ nsIContentAnalysisAcknowledgement::FinalAction ConvertResult(
} // anonymous namespace
namespace mozilla::contentanalysis {
ContentAnalysisRequest::~ContentAnalysisRequest() {
#ifdef XP_WIN
CloseHandle(mPrintDataHandle);
#endif
}
NS_IMETHODIMP
ContentAnalysisRequest::GetAnalysisType(AnalysisType* aAnalysisType) {
@ -143,34 +133,6 @@ ContentAnalysisRequest::GetFilePath(nsAString& aFilePath) {
return NS_OK;
}
NS_IMETHODIMP
ContentAnalysisRequest::GetPrintDataHandle(uint64_t* aPrintDataHandle) {
#ifdef XP_WIN
uintptr_t printDataHandle = reinterpret_cast<uintptr_t>(mPrintDataHandle);
uint64_t printDataValue = static_cast<uint64_t>(printDataHandle);
*aPrintDataHandle = printDataValue;
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
NS_IMETHODIMP
ContentAnalysisRequest::GetPrinterName(nsAString& aPrinterName) {
aPrinterName = mPrinterName;
return NS_OK;
}
NS_IMETHODIMP
ContentAnalysisRequest::GetPrintDataSize(uint64_t* aPrintDataSize) {
#ifdef XP_WIN
*aPrintDataSize = mPrintDataSize;
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
NS_IMETHODIMP
ContentAnalysisRequest::GetUrl(nsIURI** aUrl) {
NS_ENSURE_ARG_POINTER(aUrl);
@ -272,8 +234,6 @@ ContentAnalysisRequest::ContentAnalysisRequest(
mUrl(std::move(aUrl)),
mSha256Digest(std::move(aSha256Digest)),
mWindowGlobalParent(aWindowGlobalParent) {
MOZ_ASSERT(aAnalysisType != AnalysisType::ePrint,
"Print should use other ContentAnalysisRequest constructor!");
if (aStringIsFilePath) {
mFilePath = std::move(aString);
} else {
@ -291,32 +251,6 @@ ContentAnalysisRequest::ContentAnalysisRequest(
mRequestToken = GenerateRequestToken();
}
ContentAnalysisRequest::ContentAnalysisRequest(
const nsTArray<uint8_t> aPrintData, nsCOMPtr<nsIURI> aUrl,
nsString aPrinterName, dom::WindowGlobalParent* aWindowGlobalParent)
: mAnalysisType(AnalysisType::ePrint),
mUrl(std::move(aUrl)),
mPrinterName(std::move(aPrinterName)),
mWindowGlobalParent(aWindowGlobalParent) {
#ifdef XP_WIN
LARGE_INTEGER dataContentLength;
dataContentLength.QuadPart = static_cast<LONGLONG>(aPrintData.Length());
mPrintDataHandle = ::CreateFileMappingW(
INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, dataContentLength.HighPart,
dataContentLength.LowPart, nullptr);
if (mPrintDataHandle) {
mozilla::nt::AutoMappedView view(mPrintDataHandle, FILE_MAP_ALL_ACCESS);
memcpy(view.as<uint8_t>(), aPrintData.Elements(), aPrintData.Length());
mPrintDataSize = aPrintData.Length();
}
#else
MOZ_ASSERT_UNREACHABLE(
"Content Analysis is not supported on non-Windows platforms");
#endif
mOperationTypeForDisplay = OperationType::eOperationPrint;
mRequestToken = GenerateRequestToken();
}
nsresult ContentAnalysisRequest::GetFileDigest(const nsAString& aFilePath,
nsCString& aDigestString) {
MOZ_DIAGNOSTIC_ASSERT(
@ -432,44 +366,22 @@ static nsresult ConvertToProtobuf(
requestData->set_digest(sha256Digest.get());
}
if (analysisType == nsIContentAnalysisRequest::AnalysisType::ePrint) {
#if XP_WIN
uint64_t printDataHandle;
MOZ_TRY(aIn->GetPrintDataHandle(&printDataHandle));
if (!printDataHandle) {
return NS_ERROR_OUT_OF_MEMORY;
nsString filePath;
rv = aIn->GetFilePath(filePath);
NS_ENSURE_SUCCESS(rv, rv);
if (!filePath.IsEmpty()) {
std::string filePathStr = NS_ConvertUTF16toUTF8(filePath).get();
aOut->set_file_path(filePathStr);
auto filename = filePathStr.substr(filePathStr.find_last_of("/\\") + 1);
if (!filename.empty()) {
requestData->set_filename(filename);
}
aOut->mutable_print_data()->set_handle(printDataHandle);
uint64_t printDataSize;
MOZ_TRY(aIn->GetPrintDataSize(&printDataSize));
aOut->mutable_print_data()->set_size(printDataSize);
nsString printerName;
MOZ_TRY(aIn->GetPrinterName(printerName));
requestData->mutable_print_metadata()->set_printer_name(
NS_ConvertUTF16toUTF8(printerName).get());
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
} else {
nsString filePath;
rv = aIn->GetFilePath(filePath);
nsString textContent;
rv = aIn->GetTextContent(textContent);
NS_ENSURE_SUCCESS(rv, rv);
if (!filePath.IsEmpty()) {
std::string filePathStr = NS_ConvertUTF16toUTF8(filePath).get();
aOut->set_file_path(filePathStr);
auto filename = filePathStr.substr(filePathStr.find_last_of("/\\") + 1);
if (!filename.empty()) {
requestData->set_filename(filename);
}
} else {
nsString textContent;
rv = aIn->GetTextContent(textContent);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(!textContent.IsEmpty());
aOut->set_text_content(NS_ConvertUTF16toUTF8(textContent).get());
}
MOZ_ASSERT(!textContent.IsEmpty());
aOut->set_text_content(NS_ConvertUTF16toUTF8(textContent).get());
}
#ifdef XP_WIN
@ -1306,9 +1218,7 @@ void ContentAnalysis::IssueResponse(RefPtr<ContentAnalysisResponse>& response) {
LOGD("Content analysis resolving response promise for token %s",
responseRequestToken.get());
nsIContentAnalysisResponse::Action action;
DebugOnly<nsresult> rv = response->GetAction(&action);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsIContentAnalysisResponse::Action action = response->GetAction();
nsCOMPtr<nsIObserverService> obsServ =
mozilla::services::GetObserverService();
if (action == nsIContentAnalysisResponse::Action::eWarn) {
@ -1470,9 +1380,7 @@ ContentAnalysis::RespondToWarnDialog(const nsACString& aRequestToken,
return;
}
entry->mResponse->ResolveWarnAction(aAllowContent);
nsIContentAnalysisResponse::Action action;
DebugOnly<nsresult> rv = entry->mResponse->GetAction(&action);
MOZ_ASSERT(NS_SUCCEEDED(rv));
auto action = entry->mResponse->GetAction();
if (entry->mCallbackData.AutoAcknowledge()) {
RefPtr<ContentAnalysisAcknowledgement> acknowledgement =
new ContentAnalysisAcknowledgement(
@ -1497,181 +1405,6 @@ ContentAnalysis::RespondToWarnDialog(const nsACString& aRequestToken,
return NS_OK;
}
#if defined(XP_WIN)
RefPtr<ContentAnalysis::PrintAllowedPromise>
ContentAnalysis::PrintToPDFToDetermineIfPrintAllowed(
dom::CanonicalBrowsingContext* aBrowsingContext,
nsIPrintSettings* aPrintSettings) {
// Note that the IsChrome() check here excludes a few
// common about pages like about:config, about:preferences,
// and about:support, but other about: pages may still
// go through content analysis.
if (aBrowsingContext->IsChrome()) {
return PrintAllowedPromise::CreateAndResolve(PrintAllowedResult(true),
__func__);
}
nsCOMPtr<nsIPrintSettings> contentAnalysisPrintSettings;
if (NS_WARN_IF(NS_FAILED(aPrintSettings->Clone(
getter_AddRefs(contentAnalysisPrintSettings)))) ||
NS_WARN_IF(!aBrowsingContext->GetCurrentWindowGlobal())) {
return PrintAllowedPromise::CreateAndReject(
PrintAllowedError(NS_ERROR_FAILURE), __func__);
}
contentAnalysisPrintSettings->SetOutputDestination(
nsIPrintSettings::OutputDestinationType::kOutputDestinationStream);
contentAnalysisPrintSettings->SetOutputFormat(
nsIPrintSettings::kOutputFormatPDF);
nsCOMPtr<nsIStorageStream> storageStream =
do_CreateInstance("@mozilla.org/storagestream;1");
if (!storageStream) {
return PrintAllowedPromise::CreateAndReject(
PrintAllowedError(NS_ERROR_FAILURE), __func__);
}
// Use segment size of 512K
nsresult rv = storageStream->Init(0x80000, UINT32_MAX);
if (NS_WARN_IF(NS_FAILED(rv))) {
return PrintAllowedPromise::CreateAndReject(PrintAllowedError(rv),
__func__);
}
nsCOMPtr<nsIOutputStream> outputStream;
storageStream->QueryInterface(NS_GET_IID(nsIOutputStream),
getter_AddRefs(outputStream));
MOZ_ASSERT(outputStream);
contentAnalysisPrintSettings->SetOutputStream(outputStream.get());
RefPtr<dom::CanonicalBrowsingContext> browsingContext = aBrowsingContext;
auto promise = MakeRefPtr<PrintAllowedPromise::Private>(__func__);
nsCOMPtr<nsIPrintSettings> finalPrintSettings(aPrintSettings);
aBrowsingContext
->PrintWithNoContentAnalysis(contentAnalysisPrintSettings, true, nullptr)
->Then(
GetCurrentSerialEventTarget(), __func__,
[browsingContext, contentAnalysisPrintSettings, finalPrintSettings,
promise](
dom::MaybeDiscardedBrowsingContext cachedStaticBrowsingContext)
MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA mutable {
nsCOMPtr<nsIOutputStream> outputStream;
contentAnalysisPrintSettings->GetOutputStream(
getter_AddRefs(outputStream));
nsCOMPtr<nsIStorageStream> storageStream =
do_QueryInterface(outputStream);
MOZ_ASSERT(storageStream);
nsTArray<uint8_t> printData;
uint32_t length = 0;
storageStream->GetLength(&length);
if (!printData.SetLength(length, fallible)) {
promise->Reject(
PrintAllowedError(NS_ERROR_OUT_OF_MEMORY,
cachedStaticBrowsingContext),
__func__);
return;
}
nsCOMPtr<nsIInputStream> inputStream;
nsresult rv = storageStream->NewInputStream(
0, getter_AddRefs(inputStream));
if (NS_FAILED(rv)) {
promise->Reject(
PrintAllowedError(rv, cachedStaticBrowsingContext),
__func__);
return;
}
uint32_t currentPosition = 0;
while (currentPosition < length) {
uint32_t elementsRead = 0;
// Make sure the reinterpret_cast<> below is safe
static_assert(std::is_trivially_assignable_v<
decltype(*printData.Elements()), char>);
rv = inputStream->Read(
reinterpret_cast<char*>(printData.Elements()) +
currentPosition,
length - currentPosition, &elementsRead);
if (NS_WARN_IF(NS_FAILED(rv) || !elementsRead)) {
promise->Reject(
PrintAllowedError(NS_FAILED(rv) ? rv : NS_ERROR_FAILURE,
cachedStaticBrowsingContext),
__func__);
return;
}
currentPosition += elementsRead;
}
nsString printerName;
rv = contentAnalysisPrintSettings->GetPrinterName(printerName);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->Reject(
PrintAllowedError(rv, cachedStaticBrowsingContext),
__func__);
return;
}
auto* windowParent = browsingContext->GetCurrentWindowGlobal();
if (!windowParent) {
// The print window may have been closed by the user by now.
// Cancel the print.
promise->Reject(
PrintAllowedError(NS_ERROR_ABORT,
cachedStaticBrowsingContext),
__func__);
return;
}
nsCOMPtr<nsIURI> uri = windowParent->GetDocumentURI();
nsCOMPtr<nsIContentAnalysisRequest> contentAnalysisRequest =
new contentanalysis::ContentAnalysisRequest(
std::move(printData), std::move(uri),
std::move(printerName), windowParent);
auto callback =
MakeRefPtr<contentanalysis::ContentAnalysisCallback>(
[browsingContext, cachedStaticBrowsingContext, promise,
finalPrintSettings = std::move(finalPrintSettings)](
nsIContentAnalysisResponse* aResponse)
MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA mutable {
bool shouldAllow = false;
DebugOnly<nsresult> rv =
aResponse->GetShouldAllowContent(
&shouldAllow);
MOZ_ASSERT(NS_SUCCEEDED(rv));
promise->Resolve(
PrintAllowedResult(
shouldAllow, cachedStaticBrowsingContext),
__func__);
},
[promise,
cachedStaticBrowsingContext](nsresult aError) {
promise->Reject(
PrintAllowedError(aError,
cachedStaticBrowsingContext),
__func__);
});
nsCOMPtr<nsIContentAnalysis> contentAnalysis =
mozilla::components::nsIContentAnalysis::Service();
if (NS_WARN_IF(!contentAnalysis)) {
promise->Reject(
PrintAllowedError(rv, cachedStaticBrowsingContext),
__func__);
} else {
bool isActive = false;
nsresult rv = contentAnalysis->GetIsActive(&isActive);
// Should not be called if content analysis is not active
MOZ_ASSERT(isActive);
Unused << NS_WARN_IF(NS_FAILED(rv));
rv = contentAnalysis->AnalyzeContentRequestCallback(
contentAnalysisRequest, /* aAutoAcknowledge */ true,
callback);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->Reject(
PrintAllowedError(rv, cachedStaticBrowsingContext),
__func__);
}
}
},
[promise](nsresult aError) {
promise->Reject(PrintAllowedError(aError), __func__);
});
return promise;
}
#endif
NS_IMETHODIMP
ContentAnalysisResponse::Acknowledge(
nsIContentAnalysisAcknowledgement* aAcknowledgement) {

View File

@ -8,8 +8,6 @@
#include "mozilla/DataMutex.h"
#include "mozilla/MozPromise.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/MaybeDiscarded.h"
#include "mozilla/dom/Promise.h"
#include "nsIContentAnalysis.h"
#include "nsProxyRelease.h"
@ -20,16 +18,10 @@
#include <regex>
#include <string>
#ifdef XP_WIN
# include <windows.h>
#endif // XP_WIN
class nsIPrincipal;
class nsIPrintSettings;
class ContentAnalysisTest;
namespace mozilla::dom {
class CanonicalBrowsingContext;
class DataTransfer;
class WindowGlobalParent;
} // namespace mozilla::dom
@ -72,15 +64,11 @@ class ContentAnalysisRequest final : public nsIContentAnalysisRequest {
bool aStringIsFilePath, nsCString aSha256Digest,
nsCOMPtr<nsIURI> aUrl, OperationType aOperationType,
dom::WindowGlobalParent* aWindowGlobalParent);
ContentAnalysisRequest(const nsTArray<uint8_t> aPrintData,
nsCOMPtr<nsIURI> aUrl, nsString aPrinterName,
dom::WindowGlobalParent* aWindowGlobalParent);
static nsresult GetFileDigest(const nsAString& aFilePath,
nsCString& aDigestString);
private:
~ContentAnalysisRequest();
~ContentAnalysisRequest() = default;
// Remove unneeded copy constructor/assignment
ContentAnalysisRequest(const ContentAnalysisRequest&) = delete;
ContentAnalysisRequest& operator=(ContentAnalysisRequest&) = delete;
@ -117,16 +105,7 @@ class ContentAnalysisRequest final : public nsIContentAnalysisRequest {
// OPERATION_CUSTOMDISPLAYSTRING
nsString mOperationDisplayString;
// The name of the printer being printed to
nsString mPrinterName;
RefPtr<dom::WindowGlobalParent> mWindowGlobalParent;
#ifdef XP_WIN
// The printed data to analyze, in PDF format
HANDLE mPrintDataHandle = 0;
// The size of the printed data in mPrintDataHandle
uint64_t mPrintDataSize = 0;
#endif
friend class ::ContentAnalysisTest;
};
@ -149,39 +128,6 @@ class ContentAnalysis final : public nsIContentAnalysis {
nsCString GetUserActionId();
void SetLastResult(nsresult aLastResult) { mLastResult = aLastResult; }
struct PrintAllowedResult final {
bool mAllowed;
dom::MaybeDiscarded<dom::BrowsingContext>
mCachedStaticDocumentBrowsingContext;
PrintAllowedResult(bool aAllowed, dom::MaybeDiscarded<dom::BrowsingContext>
aCachedStaticDocumentBrowsingContext)
: mAllowed(aAllowed),
mCachedStaticDocumentBrowsingContext(
aCachedStaticDocumentBrowsingContext) {}
explicit PrintAllowedResult(bool aAllowed)
: PrintAllowedResult(aAllowed, dom::MaybeDiscardedBrowsingContext()) {}
};
struct PrintAllowedError final {
nsresult mError;
dom::MaybeDiscarded<dom::BrowsingContext>
mCachedStaticDocumentBrowsingContext;
PrintAllowedError(nsresult aError, dom::MaybeDiscarded<dom::BrowsingContext>
aCachedStaticDocumentBrowsingContext)
: mError(aError),
mCachedStaticDocumentBrowsingContext(
aCachedStaticDocumentBrowsingContext) {}
explicit PrintAllowedError(nsresult aError)
: PrintAllowedError(aError, dom::MaybeDiscardedBrowsingContext()) {}
};
using PrintAllowedPromise =
MozPromise<PrintAllowedResult, PrintAllowedError, true>;
#if defined(XP_WIN)
MOZ_CAN_RUN_SCRIPT static RefPtr<PrintAllowedPromise>
PrintToPDFToDetermineIfPrintAllowed(
dom::CanonicalBrowsingContext* aBrowsingContext,
nsIPrintSettings* aPrintSettings);
#endif // defined(XP_WIN)
private:
~ContentAnalysis();
// Remove unneeded copy constructor/assignment

View File

@ -87,11 +87,7 @@ class ContentAnalysisResult : public nsIContentAnalysisResult {
static RefPtr<ContentAnalysisResult> FromContentAnalysisResponse(
nsIContentAnalysisResponse* aResponse) {
bool shouldAllowContent = false;
DebugOnly<nsresult> rv =
aResponse->GetShouldAllowContent(&shouldAllowContent);
MOZ_ASSERT(NS_SUCCEEDED(rv));
if (shouldAllowContent) {
if (aResponse->GetShouldAllowContent()) {
return FromAction(nsIContentAnalysisResponse::Action::eAllow);
} else {
return FromAction(nsIContentAnalysisResponse::Action::eBlock);

View File

@ -11,6 +11,5 @@ Classes = [
'contract_ids': ['@mozilla.org/contentanalysis;1'],
'type': 'mozilla::contentanalysis::ContentAnalysis',
'headers': ['/toolkit/components/contentanalysis/ContentAnalysis.h'],
'overridable': True,
},
]

View File

@ -36,7 +36,7 @@ interface nsIContentAnalysisAcknowledgement : nsISupports
readonly attribute nsIContentAnalysisAcknowledgement_FinalAction finalAction;
};
[scriptable, uuid(89088c61-15f6-4ace-a880-a1b5ea47ca66)]
[scriptable, builtinclass, uuid(89088c61-15f6-4ace-a880-a1b5ea47ca66)]
interface nsIContentAnalysisResponse : nsISupports
{
// These values must stay synchronized with ContentAnalysisResponse
@ -59,11 +59,11 @@ interface nsIContentAnalysisResponse : nsISupports
eErrorOther = 3,
};
readonly attribute nsIContentAnalysisResponse_Action action;
readonly attribute boolean shouldAllowContent;
[infallible] readonly attribute nsIContentAnalysisResponse_Action action;
[infallible] readonly attribute boolean shouldAllowContent;
// If action is eCanceled, this is the error explaining why the request was canceled,
// or eUserInitiated if the user canceled it.
readonly attribute nsIContentAnalysisResponse_CancelError cancelError;
[infallible] readonly attribute nsIContentAnalysisResponse_CancelError cancelError;
// Identifier for the corresponding nsIContentAnalysisRequest
readonly attribute ACString requestToken;
@ -131,7 +131,6 @@ interface nsIContentAnalysisRequest : nsISupports
eCustomDisplayString = 0,
eClipboard = 1,
eDroppedText = 2,
eOperationPrint = 3,
};
readonly attribute nsIContentAnalysisRequest_OperationType operationTypeForDisplay;
readonly attribute AString operationDisplayString;
@ -142,15 +141,6 @@ interface nsIContentAnalysisRequest : nsISupports
// Name of file to analyze. Only one of textContent or filePath is defined.
readonly attribute AString filePath;
// HANDLE to the printed data in PDF format.
readonly attribute unsigned long long printDataHandle;
// Size of the data stored in printDataHandle.
readonly attribute unsigned long long printDataSize;
// Name of the printer being printed to.
readonly attribute AString printerName;
// The URL containing the file download/upload or to which web content is
// being uploaded.
readonly attribute nsIURI url;
@ -195,7 +185,7 @@ interface nsIContentAnalysisDiagnosticInfo : nsISupports
[infallible] readonly attribute long long requestCount;
};
[scriptable, uuid(61497587-2bba-4a88-acd3-3fbb2cedf163)]
[scriptable, builtinclass, uuid(61497587-2bba-4a88-acd3-3fbb2cedf163)]
interface nsIContentAnalysis : nsISupports
{
/**

View File

@ -1,20 +1,3 @@
[DEFAULT]
run-if = ["os == 'win'"]
support-files = [
"head.js",
]
["browser_content_analysis_policies.js"]
["browser_print_changing_page_content_analysis.js"]
support-files = [
"!/toolkit/components/printing/tests/head.js",
"changing_page_for_print.html",
]
["browser_print_content_analysis.js"]
support-files = [
"!/toolkit/components/printing/tests/head.js",
"!/toolkit/components/printing/tests/longerArticle.html",
"!/toolkit/components/printing/tests/simplifyArticleSample.html",
]

View File

@ -1,339 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/toolkit/components/printing/tests/head.js",
this
);
const PSSVC = Cc["@mozilla.org/gfx/printsettings-service;1"].getService(
Ci.nsIPrintSettingsService
);
let mockCA = {
isActive: true,
mightBeActive: true,
errorValue: undefined,
setupForTest(shouldAllowRequest) {
this.shouldAllowRequest = shouldAllowRequest;
this.errorValue = undefined;
this.calls = [];
},
setupForTestWithError(errorValue) {
this.errorValue = errorValue;
this.calls = [];
},
getAction() {
if (this.shouldAllowRequest === undefined) {
this.shouldAllowRequest = true;
}
return this.shouldAllowRequest
? Ci.nsIContentAnalysisResponse.eAllow
: Ci.nsIContentAnalysisResponse.eBlock;
},
// nsIContentAnalysis methods
async analyzeContentRequest(request, _autoAcknowledge) {
info(
"Mock ContentAnalysis service: analyzeContentRequest, this.shouldAllowRequest=" +
this.shouldAllowRequest +
", this.errorValue=" +
this.errorValue
);
this.calls.push(request);
if (this.errorValue) {
throw this.errorValue;
}
// Use setTimeout to simulate an async activity
await new Promise(res => setTimeout(res, 0));
return makeContentAnalysisResponse(this.getAction(), request.requestToken);
},
analyzeContentRequestCallback(request, autoAcknowledge, callback) {
info(
"Mock ContentAnalysis service: analyzeContentRequestCallback, this.shouldAllowRequest=" +
this.shouldAllowRequest +
", this.errorValue=" +
this.errorValue
);
this.calls.push(request);
if (this.errorValue) {
throw this.errorValue;
}
let response = makeContentAnalysisResponse(
this.getAction(),
request.requestToken
);
// Use setTimeout to simulate an async activity
setTimeout(() => {
callback.contentResult(response);
}, 0);
},
};
add_setup(async function test_setup() {
mockCA = mockContentAnalysisService(mockCA);
});
const TEST_PAGE_URL = PrintHelper.getTestPageUrlHTTPS(
"changing_page_for_print.html"
);
function addUniqueSuffix(prefix) {
return `${prefix}-${Services.uuid
.generateUUID()
.toString()
.slice(1, -1)}.pdf`;
}
async function printToDestination(aBrowser, aDestination) {
let tmpDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
let fileName = addUniqueSuffix(`printDestinationTest-${aDestination}`);
let filePath = PathUtils.join(tmpDir.path, fileName);
info(`Printing to ${filePath}`);
let settings = PSSVC.createNewPrintSettings();
settings.outputFormat = Ci.nsIPrintSettings.kOutputFormatPDF;
settings.outputDestination = aDestination;
settings.headerStrCenter = "";
settings.headerStrLeft = "";
settings.headerStrRight = "";
settings.footerStrCenter = "";
settings.footerStrLeft = "";
settings.footerStrRight = "";
settings.unwriteableMarginTop = 1; /* Just to ensure settings are respected on both */
let outStream = null;
if (aDestination == Ci.nsIPrintSettings.kOutputDestinationFile) {
settings.toFileName = PathUtils.join(tmpDir.path, fileName);
} else {
is(aDestination, Ci.nsIPrintSettings.kOutputDestinationStream);
outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
Ci.nsIFileOutputStream
);
let tmpFile = tmpDir.clone();
tmpFile.append(fileName);
outStream.init(tmpFile, -1, 0o666, 0);
settings.outputStream = outStream;
}
await aBrowser.browsingContext.print(settings);
return filePath;
}
function assertContentAnalysisRequest(request) {
is(request.url.spec, TEST_PAGE_URL, "request has correct URL");
is(
request.analysisType,
Ci.nsIContentAnalysisRequest.ePrint,
"request has print analysisType"
);
is(
request.operationTypeForDisplay,
Ci.nsIContentAnalysisRequest.eOperationPrint,
"request has print operationTypeForDisplay"
);
is(request.textContent, "", "request textContent should be empty");
is(request.filePath, "", "request filePath should be empty");
isnot(request.printDataHandle, 0, "request printDataHandle should not be 0");
isnot(request.printDataSize, 0, "request printDataSize should not be 0");
ok(!!request.requestToken.length, "request requestToken should not be empty");
}
add_task(
async function testPrintToStreamWithContentAnalysisActiveAndAllowing() {
await PrintHelper.withTestPage(
async helper => {
mockCA.setupForTest(true);
let filePath = await printToDestination(
helper.sourceBrowser,
Ci.nsIPrintSettings.kOutputDestinationFile
);
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0]);
// This effectively tests that the PDF content sent to Content Analysis
// and the content that is actually printed matches. This is necessary
// because a previous iteration of the Content Analysis code didn't use
// a static Document clone for this and so the content would differ. (since
// the .html file in question adds content to the page when print events
// happen)
await waitForFileToAlmostMatchSize(
filePath,
mockCA.calls[0].printDataSize
);
await IOUtils.remove(filePath);
},
TEST_PAGE_URL,
true
);
}
);
add_task(
async function testPrintToStreamWithContentAnalysisActiveAndBlocking() {
await PrintHelper.withTestPage(
async helper => {
mockCA.setupForTest(false);
try {
await printToDestination(
helper.sourceBrowser,
Ci.nsIPrintSettings.kOutputDestinationFile
);
ok(false, "Content analysis should make this fail to print");
} catch (e) {
ok(
/NS_ERROR_CONTENT_BLOCKED/.test(e.toString()),
"Got content blocked error"
);
}
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0]);
},
TEST_PAGE_URL,
true
);
}
);
add_task(async function testPrintToStreamWithContentAnalysisReturningError() {
await PrintHelper.withTestPage(
async helper => {
expectUncaughtException();
mockCA.setupForTestWithError(Cr.NS_ERROR_NOT_AVAILABLE);
try {
await printToDestination(
helper.sourceBrowser,
Ci.nsIPrintSettings.kOutputDestinationFile
);
ok(false, "Content analysis should make this fail to print");
} catch (e) {
ok(
/NS_ERROR_NOT_AVAILABLE/.test(e.toString()),
"Error in mock CA was propagated out"
);
}
is(mockCA.calls.length, 1, "Correct number of calls to Content Analysis");
assertContentAnalysisRequest(mockCA.calls[0]);
},
TEST_PAGE_URL,
true
);
});
add_task(async function testPrintThroughDialogWithContentAnalysisActive() {
await PrintHelper.withTestPage(
async helper => {
mockCA.setupForTest(true);
let fileName = addUniqueSuffix(`printDialogTest`);
let file = helper.mockFilePicker(fileName);
info(`Printing to ${file.path}`);
await helper.startPrint();
await helper.assertPrintToFile(file, () => {
EventUtils.sendKey("return", helper.win);
});
is(mockCA.calls.length, 1, "Correct number of calls to Content Analysis");
assertContentAnalysisRequest(mockCA.calls[0]);
await waitForFileToAlmostMatchSize(
file.path,
mockCA.calls[0].printDataSize
);
},
TEST_PAGE_URL,
true
);
});
add_task(
async function testPrintThroughDialogWithContentAnalysisActiveAndBlocking() {
await PrintHelper.withTestPage(
async helper => {
mockCA.setupForTest(false);
await helper.startPrint();
let fileName = addUniqueSuffix(`printDialogTest`);
let file = helper.mockFilePicker(fileName);
info(`Printing to ${file.path}`);
try {
await helper.assertPrintToFile(file, () => {
EventUtils.sendKey("return", helper.win);
});
} catch (e) {
ok(
/Wait for target file to get created/.test(e.toString()),
"Target file should not get created"
);
}
ok(!file.exists(), "File should not exist");
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0]);
},
TEST_PAGE_URL,
true
);
}
);
add_task(
async function testPrintThroughDialogWithContentAnalysisReturningError() {
await PrintHelper.withTestPage(
async helper => {
expectUncaughtException();
mockCA.setupForTestWithError(Cr.NS_ERROR_NOT_AVAILABLE);
await helper.startPrint();
let fileName = addUniqueSuffix(`printDialogTest`);
let file = helper.mockFilePicker(fileName);
info(`Printing to ${file.path}`);
try {
await helper.assertPrintToFile(file, () => {
EventUtils.sendKey("return", helper.win);
});
} catch (e) {
ok(
/Wait for target file to get created/.test(e.toString()),
"Target file should not get created"
);
}
ok(!file.exists(), "File should not exist");
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0]);
},
TEST_PAGE_URL,
true
);
}
);

View File

@ -1,390 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/toolkit/components/printing/tests/head.js",
this
);
const PSSVC = Cc["@mozilla.org/gfx/printsettings-service;1"].getService(
Ci.nsIPrintSettingsService
);
let mockCA = {
isActive: true,
mightBeActive: true,
errorValue: undefined,
setupForTest(shouldAllowRequest) {
this.shouldAllowRequest = shouldAllowRequest;
this.errorValue = undefined;
this.calls = [];
},
setupForTestWithError(errorValue) {
this.errorValue = errorValue;
this.calls = [];
},
clearCalls() {
this.calls = [];
},
getAction() {
if (this.shouldAllowRequest === undefined) {
this.shouldAllowRequest = true;
}
return this.shouldAllowRequest
? Ci.nsIContentAnalysisResponse.eAllow
: Ci.nsIContentAnalysisResponse.eBlock;
},
// nsIContentAnalysis methods
async analyzeContentRequest(request, _autoAcknowledge) {
info(
"Mock ContentAnalysis service: analyzeContentRequest, this.shouldAllowRequest=" +
this.shouldAllowRequest +
", this.errorValue=" +
this.errorValue
);
this.calls.push(request);
if (this.errorValue) {
throw this.errorValue;
}
// Use setTimeout to simulate an async activity
await new Promise(res => setTimeout(res, 0));
return makeContentAnalysisResponse(this.getAction(), request.requestToken);
},
analyzeContentRequestCallback(request, autoAcknowledge, callback) {
info(
"Mock ContentAnalysis service: analyzeContentRequestCallback, this.shouldAllowRequest=" +
this.shouldAllowRequest +
", this.errorValue=" +
this.errorValue
);
this.calls.push(request);
if (this.errorValue) {
throw this.errorValue;
}
let response = makeContentAnalysisResponse(
this.getAction(),
request.requestToken
);
// Use setTimeout to simulate an async activity
setTimeout(() => {
callback.contentResult(response);
}, 0);
},
};
add_setup(async function test_setup() {
mockCA = mockContentAnalysisService(mockCA);
});
const TEST_PAGE_URL =
"https://example.com/browser/toolkit/components/printing/tests/simplifyArticleSample.html";
const TEST_PAGE_URL_2 =
"https://example.com/browser/toolkit/components/printing/tests/longerArticle.html";
function addUniqueSuffix(prefix) {
return `${prefix}-${Services.uuid
.generateUUID()
.toString()
.slice(1, -1)}.pdf`;
}
async function printToDestination(aBrowser, aDestination) {
let tmpDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
let fileName = addUniqueSuffix(`printDestinationTest-${aDestination}`);
let filePath = PathUtils.join(tmpDir.path, fileName);
info(`Printing to ${filePath}`);
let settings = PSSVC.createNewPrintSettings();
settings.outputFormat = Ci.nsIPrintSettings.kOutputFormatPDF;
settings.outputDestination = aDestination;
settings.headerStrCenter = "";
settings.headerStrLeft = "";
settings.headerStrRight = "";
settings.footerStrCenter = "";
settings.footerStrLeft = "";
settings.footerStrRight = "";
settings.unwriteableMarginTop = 1; /* Just to ensure settings are respected on both */
let outStream = null;
if (aDestination == Ci.nsIPrintSettings.kOutputDestinationFile) {
settings.toFileName = PathUtils.join(tmpDir.path, fileName);
} else {
is(aDestination, Ci.nsIPrintSettings.kOutputDestinationStream);
outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
Ci.nsIFileOutputStream
);
let tmpFile = tmpDir.clone();
tmpFile.append(fileName);
outStream.init(tmpFile, -1, 0o666, 0);
settings.outputStream = outStream;
}
await aBrowser.browsingContext.print(settings);
return filePath;
}
function assertContentAnalysisRequest(request, expectedUrl) {
is(request.url.spec, expectedUrl ?? TEST_PAGE_URL, "request has correct URL");
is(
request.analysisType,
Ci.nsIContentAnalysisRequest.ePrint,
"request has print analysisType"
);
is(
request.operationTypeForDisplay,
Ci.nsIContentAnalysisRequest.eOperationPrint,
"request has print operationTypeForDisplay"
);
is(request.textContent, "", "request textContent should be empty");
is(request.filePath, "", "request filePath should be empty");
isnot(request.printDataHandle, 0, "request printDataHandle should not be 0");
isnot(request.printDataSize, 0, "request printDataSize should not be 0");
ok(!!request.requestToken.length, "request requestToken should not be empty");
}
// Printing to a stream is different than going through the print preview dialog because it
// doesn't make a static clone of the document before the print, which causes the
// Content Analysis code to go through a different code path. This is similar to what
// happens when various preferences are set to skip the print preview dialog, for example
// print.prefer_system_dialog.
add_task(
async function testPrintToStreamWithContentAnalysisActiveAndAllowing() {
await PrintHelper.withTestPage(
async helper => {
mockCA.setupForTest(true);
let filePath = await printToDestination(
helper.sourceBrowser,
Ci.nsIPrintSettings.kOutputDestinationFile
);
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0]);
await waitForFileToAlmostMatchSize(
filePath,
mockCA.calls[0].printDataSize
);
await IOUtils.remove(filePath);
},
TEST_PAGE_URL,
true
);
}
);
add_task(
async function testPrintToStreamAfterNavigationWithContentAnalysisActiveAndAllowing() {
await PrintHelper.withTestPage(
async helper => {
mockCA.setupForTest(true);
let filePath = await printToDestination(
helper.sourceBrowser,
Ci.nsIPrintSettings.kOutputDestinationFile
);
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0]);
mockCA.clearCalls();
await IOUtils.remove(filePath);
BrowserTestUtils.startLoadingURIString(
helper.sourceBrowser,
TEST_PAGE_URL_2
);
await BrowserTestUtils.browserLoaded(helper.sourceBrowser);
filePath = await printToDestination(
helper.sourceBrowser,
Ci.nsIPrintSettings.kOutputDestinationFile
);
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0], TEST_PAGE_URL_2);
await waitForFileToAlmostMatchSize(
filePath,
mockCA.calls[0].printDataSize
);
},
TEST_PAGE_URL,
true
);
}
);
add_task(
async function testPrintToStreamWithContentAnalysisActiveAndBlocking() {
await PrintHelper.withTestPage(
async helper => {
mockCA.setupForTest(false);
try {
await printToDestination(
helper.sourceBrowser,
Ci.nsIPrintSettings.kOutputDestinationFile
);
ok(false, "Content analysis should make this fail to print");
} catch (e) {
ok(
/NS_ERROR_CONTENT_BLOCKED/.test(e.toString()),
"Got content blocked error"
);
}
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0]);
},
TEST_PAGE_URL,
true
);
}
);
add_task(async function testPrintToStreamWithContentAnalysisReturningError() {
await PrintHelper.withTestPage(
async helper => {
expectUncaughtException();
mockCA.setupForTestWithError(Cr.NS_ERROR_NOT_AVAILABLE);
try {
await printToDestination(
helper.sourceBrowser,
Ci.nsIPrintSettings.kOutputDestinationFile
);
ok(false, "Content analysis should make this fail to print");
} catch (e) {
ok(
/NS_ERROR_NOT_AVAILABLE/.test(e.toString()),
"Error in mock CA was propagated out"
);
}
is(mockCA.calls.length, 1, "Correct number of calls to Content Analysis");
assertContentAnalysisRequest(mockCA.calls[0]);
},
TEST_PAGE_URL,
true
);
});
add_task(async function testPrintThroughDialogWithContentAnalysisActive() {
await PrintHelper.withTestPage(
async helper => {
mockCA.setupForTest(true);
await helper.startPrint();
let fileName = addUniqueSuffix(`printDialogTest`);
let file = helper.mockFilePicker(fileName);
info(`Printing to ${file.path}`);
await helper.assertPrintToFile(file, () => {
EventUtils.sendKey("return", helper.win);
});
is(mockCA.calls.length, 1, "Correct number of calls to Content Analysis");
assertContentAnalysisRequest(mockCA.calls[0]);
await waitForFileToAlmostMatchSize(
file.path,
mockCA.calls[0].printDataSize
);
},
TEST_PAGE_URL,
true
);
});
add_task(
async function testPrintThroughDialogWithContentAnalysisActiveAndBlocking() {
await PrintHelper.withTestPage(
async helper => {
mockCA.setupForTest(false);
await helper.startPrint();
let fileName = addUniqueSuffix(`printDialogTest`);
let file = helper.mockFilePicker(fileName);
info(`Printing to ${file.path}`);
try {
await helper.assertPrintToFile(file, () => {
EventUtils.sendKey("return", helper.win);
});
} catch (e) {
ok(
/Wait for target file to get created/.test(e.toString()),
"Target file should not get created"
);
}
ok(!file.exists(), "File should not exist");
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0]);
},
TEST_PAGE_URL,
true
);
}
);
add_task(
async function testPrintThroughDialogWithContentAnalysisReturningError() {
await PrintHelper.withTestPage(
async helper => {
expectUncaughtException();
mockCA.setupForTestWithError(Cr.NS_ERROR_NOT_AVAILABLE);
await helper.startPrint();
let fileName = addUniqueSuffix(`printDialogTest`);
let file = helper.mockFilePicker(fileName);
info(`Printing to ${file.path}`);
try {
await helper.assertPrintToFile(file, () => {
EventUtils.sendKey("return", helper.win);
});
} catch (e) {
ok(
/Wait for target file to get created/.test(e.toString()),
"Target file should not get created"
);
}
ok(!file.exists(), "File should not exist");
is(
mockCA.calls.length,
1,
"Correct number of calls to Content Analysis"
);
assertContentAnalysisRequest(mockCA.calls[0]);
},
TEST_PAGE_URL,
true
);
}
);

View File

@ -1,12 +0,0 @@
<!doctype html>
<p>Some random text</p>
<button onclick="print()">Print the page</button>
<pre id="log"></pre>
<script>
let i = 0;
for (let t of ["beforeprint", "afterprint"]) {
addEventListener(t, () => {
document.getElementById("log").appendChild(document.createTextNode(`[${i++}] ${t}\n`));
});
}
</script>

View File

@ -1,114 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { MockRegistrar } = ChromeUtils.importESModule(
"resource://testing-common/MockRegistrar.sys.mjs"
);
// Wraps the given object in an XPConnect wrapper and, if an interface
// is passed, queries the result to that interface.
function xpcWrap(obj, iface) {
let ifacePointer = Cc[
"@mozilla.org/supports-interface-pointer;1"
].createInstance(Ci.nsISupportsInterfacePointer);
ifacePointer.data = obj;
if (iface) {
return ifacePointer.data.QueryInterface(iface);
}
return ifacePointer.data;
}
/**
* Mock a (set of) service(s) as the object mockService.
*
* @param {[string]} serviceNames
* array of services names that mockService will be
* allowed to QI to. Must include the name of the
* service referenced by contractId.
* @param {string} contractId
* the component ID that will reference the mock object
* instead of the original service
* @param {object} interfaceObj
* interface object for the component
* @param {object} mockService
* object that satisfies the contract well
* enough to use as a mock of it
* @returns {object} The newly-mocked service
*/
function mockService(serviceNames, contractId, interfaceObj, mockService) {
// xpcWrap allows us to mock [implicit_jscontext] methods.
let newService = {
...mockService,
QueryInterface: ChromeUtils.generateQI(serviceNames),
};
let o = xpcWrap(newService, interfaceObj);
let cid = MockRegistrar.register(contractId, o);
registerCleanupFunction(() => {
MockRegistrar.unregister(cid);
});
return newService;
}
/**
* Mock the nsIContentAnalysis service with the object mockCAService.
*
* @param {object} mockCAService
* the service to mock for nsIContentAnalysis
* @returns {object} The newly-mocked service
*/
function mockContentAnalysisService(mockCAService) {
return mockService(
["nsIContentAnalysis"],
"@mozilla.org/contentanalysis;1",
Ci.nsIContentAnalysis,
mockCAService
);
}
/**
* Make an nsIContentAnalysisResponse.
*
* @param {number} action The action to take, from the
* nsIContentAnalysisResponse.Action enum.
* @param {string} token The requestToken.
* @returns {object} An object that conforms to nsIContentAnalysisResponse.
*/
function makeContentAnalysisResponse(action, token) {
return {
action,
shouldAllowContent: action != Ci.nsIContentAnalysisResponse.eBlock,
requestToken: token,
acknowledge: _acknowledgement => {},
};
}
async function waitForFileToAlmostMatchSize(filePath, expectedSize) {
// In Cocoa the CGContext adds a hash, plus there are other minor
// non-user-visible differences, so we need to be a bit more sloppy there.
//
// We see one byte difference in Windows and Linux on automation sometimes,
// though files are consistently the same locally, that needs
// investigation, but it's probably harmless.
// Note that this is copied from browser_print_stream.js.
const maxSizeDifference = AppConstants.platform == "macosx" ? 100 : 3;
// Buffering shenanigans? Wait for sizes to match... There's no great
// IOUtils methods to force a flush without writing anything...
// Note that this means if this results in a timeout this is exactly
// the same as a test failure.
// This is taken from toolkit/components/printing/tests/browser_print_stream.js
await TestUtils.waitForCondition(async function () {
let fileStat = await IOUtils.stat(filePath);
info("got size: " + fileStat.size + " expected: " + expectedSize);
Assert.greater(
fileStat.size,
0,
"File should not be empty: " + fileStat.size
);
return Math.abs(fileStat.size - expectedSize) <= maxSizeDifference;
}, "Sizes should (almost) match");
}

View File

@ -60,9 +60,6 @@ class PrintHelper {
}
static getTestPageUrl(pathName) {
if (pathName.startsWith("http://")) {
return pathName;
}
const testPath = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
@ -71,9 +68,6 @@ class PrintHelper {
}
static getTestPageUrlHTTPS(pathName) {
if (pathName.startsWith("https://")) {
return pathName;
}
const testPath = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"

View File

@ -20,12 +20,8 @@ contentanalysis-slow-agent-dialog-body-clipboard = { $agent } is reviewing what
# Variables:
# $agent - The name of the DLP agent doing the analysis
contentanalysis-slow-agent-dialog-body-dropped-text = { $agent } is reviewing the text you dropped against your organizations data policies. This may take a moment.
# Variables:
# $agent - The name of the DLP agent doing the analysis
contentanalysis-slow-agent-dialog-body-print = { $agent } is reviewing what you printed against your organizations data policies. This may take a moment.
contentanalysis-operationtype-clipboard = clipboard
contentanalysis-operationtype-dropped-text = dropped text
contentanalysis-operationtype-print = print
# $filename - The filename associated with the request, such as "aFile.txt"
contentanalysis-customdisplaystring-description = upload of “{ $filename }”

View File

@ -335,7 +335,7 @@ interface nsIPrintSettings : nsISupports
*/
attribute AString toFileName;
attribute nsIOutputStream outputStream; /* for kOutputDestinationStream */
attribute nsIOutputStream outputStream; /* for kOutputDestinationPrinter */
[infallible] attribute long printPageDelay; /* in milliseconds */

View File

@ -735,11 +735,7 @@ nsFilePicker::CheckContentAnalysisService() {
auto contentAnalysisCallback =
mozilla::MakeRefPtr<mozilla::contentanalysis::ContentAnalysisCallback>(
[promise](nsIContentAnalysisResponse* aResponse) {
bool shouldAllow = false;
mozilla::DebugOnly<nsresult> rv =
aResponse->GetShouldAllowContent(&shouldAllow);
MOZ_ASSERT(NS_SUCCEEDED(rv));
promise->Resolve(shouldAllow, __func__);
promise->Resolve(aResponse->GetShouldAllowContent(), __func__);
},
[promise](nsresult aError) { promise->Reject(aError, __func__); });