diff options
Diffstat (limited to 'layout/printing/ipc')
-rw-r--r-- | layout/printing/ipc/PRemotePrintJob.ipdl | 58 | ||||
-rw-r--r-- | layout/printing/ipc/RemotePrintJobChild.cpp | 155 | ||||
-rw-r--r-- | layout/printing/ipc/RemotePrintJobChild.h | 61 | ||||
-rw-r--r-- | layout/printing/ipc/RemotePrintJobParent.cpp | 244 | ||||
-rw-r--r-- | layout/printing/ipc/RemotePrintJobParent.h | 84 |
5 files changed, 602 insertions, 0 deletions
diff --git a/layout/printing/ipc/PRemotePrintJob.ipdl b/layout/printing/ipc/PRemotePrintJob.ipdl new file mode 100644 index 000000000..f6c1de895 --- /dev/null +++ b/layout/printing/ipc/PRemotePrintJob.ipdl @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PPrinting; + +namespace mozilla { +namespace layout { + +async protocol PRemotePrintJob +{ + manager PPrinting; + +both: + // Tell either side to abort printing and clean up. + async AbortPrint(nsresult aRv); + +parent: + // Initialize the real print device with the given information. + async InitializePrint(nsString aDocumentTitle, nsString aPrintToFile, + int32_t aStartPage, int32_t aEndPage); + + // Translate the stored page recording and play back the events to the real + // print device. + async ProcessPage(nsCString aPageFileName); + + // This informs the real print device that we've finished, so it can trigger + // the actual print. + async FinalizePrint(); + + // Report a state change to listeners in the parent process. + async StateChange(long aStateFlags, + nsresult aStatus); + + // Report a progress change to listeners in the parent process. + async ProgressChange(long aCurSelfProgress, + long aMaxSelfProgress, + long aCurTotalProgress, + long aMaxTotalProgress); + + // Report a status change to listeners in the parent process. + async StatusChange(nsresult aStatus); + +child: + // Inform the child that the print has been initialized in the parent or has + // failed with result aRv. + async PrintInitializationResult(nsresult aRv); + + // Inform the child that the latest page has been processed remotely. + async PageProcessed(); + + async __delete__(); +}; + +} // namespace layout +} // namespace mozilla diff --git a/layout/printing/ipc/RemotePrintJobChild.cpp b/layout/printing/ipc/RemotePrintJobChild.cpp new file mode 100644 index 000000000..ffc3c2455 --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobChild.cpp @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemotePrintJobChild.h" + +#include "mozilla/Unused.h" +#include "nsPagePrintTimer.h" +#include "nsPrintEngine.h" + +namespace mozilla { +namespace layout { + +NS_IMPL_ISUPPORTS(RemotePrintJobChild, + nsIWebProgressListener) + +RemotePrintJobChild::RemotePrintJobChild() +{ + MOZ_COUNT_CTOR(RemotePrintJobChild); +} + +nsresult +RemotePrintJobChild::InitializePrint(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage) +{ + // Print initialization can sometimes display a dialog in the parent, so we + // need to spin a nested event loop until initialization completes. + Unused << SendInitializePrint(aDocumentTitle, aPrintToFile, aStartPage, + aEndPage); + while (!mPrintInitialized) { + Unused << NS_ProcessNextEvent(); + } + + return mInitializationResult; +} + +bool +RemotePrintJobChild::RecvPrintInitializationResult(const nsresult& aRv) +{ + mPrintInitialized = true; + mInitializationResult = aRv; + return true; +} + +void +RemotePrintJobChild::ProcessPage(const nsCString& aPageFileName) +{ + MOZ_ASSERT(mPagePrintTimer); + + mPagePrintTimer->WaitForRemotePrint(); + Unused << SendProcessPage(aPageFileName); +} + +bool +RemotePrintJobChild::RecvPageProcessed() +{ + MOZ_ASSERT(mPagePrintTimer); + + mPagePrintTimer->RemotePrintFinished(); + return true; +} + +bool +RemotePrintJobChild::RecvAbortPrint(const nsresult& aRv) +{ + MOZ_ASSERT(mPrintEngine); + + mPrintEngine->CleanupOnFailure(aRv, true); + return true; +} + +void +RemotePrintJobChild::SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer) +{ + MOZ_ASSERT(aPagePrintTimer); + + mPagePrintTimer = aPagePrintTimer; +} + +void +RemotePrintJobChild::SetPrintEngine(nsPrintEngine* aPrintEngine) +{ + MOZ_ASSERT(aPrintEngine); + + mPrintEngine = aPrintEngine; +} + +// nsIWebProgressListener + +NS_IMETHODIMP +RemotePrintJobChild::OnStateChange(nsIWebProgress* aProgress, + nsIRequest* aRequest, uint32_t aStateFlags, + nsresult aStatus) +{ + Unused << SendStateChange(aStateFlags, aStatus); + return NS_OK; +} + +NS_IMETHODIMP +RemotePrintJobChild::OnProgressChange(nsIWebProgress * aProgress, + nsIRequest * aRequest, + int32_t aCurSelfProgress, + int32_t aMaxSelfProgress, + int32_t aCurTotalProgress, + int32_t aMaxTotalProgress) +{ + Unused << SendProgressChange(aCurSelfProgress, aMaxSelfProgress, + aCurTotalProgress, aMaxTotalProgress); + return NS_OK; +} + +NS_IMETHODIMP +RemotePrintJobChild::OnLocationChange(nsIWebProgress* aProgress, + nsIRequest* aRequest, nsIURI* aURI, + uint32_t aFlags) +{ + return NS_OK; +} + +NS_IMETHODIMP +RemotePrintJobChild::OnStatusChange(nsIWebProgress* aProgress, + nsIRequest* aRequest, nsresult aStatus, + const char16_t* aMessage) +{ + Unused << SendStatusChange(aStatus); + return NS_OK; +} + +NS_IMETHODIMP +RemotePrintJobChild::OnSecurityChange(nsIWebProgress* aProgress, + nsIRequest* aRequest, uint32_t aState) +{ + return NS_OK; +} + +// End of nsIWebProgressListener + +RemotePrintJobChild::~RemotePrintJobChild() +{ + MOZ_COUNT_DTOR(RemotePrintJobChild); +} + +void +RemotePrintJobChild::ActorDestroy(ActorDestroyReason aWhy) +{ + mPagePrintTimer = nullptr; + mPrintEngine = nullptr; +} + +} // namespace layout +} // namespace mozilla diff --git a/layout/printing/ipc/RemotePrintJobChild.h b/layout/printing/ipc/RemotePrintJobChild.h new file mode 100644 index 000000000..a316815ea --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobChild.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layout_RemotePrintJobChild_h +#define mozilla_layout_RemotePrintJobChild_h + +#include "mozilla/layout/PRemotePrintJobChild.h" + +#include "mozilla/RefPtr.h" +#include "nsIWebProgressListener.h" + +class nsPagePrintTimer; +class nsPrintEngine; + +namespace mozilla { +namespace layout { + +class RemotePrintJobChild final : public PRemotePrintJobChild + , public nsIWebProgressListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBPROGRESSLISTENER + + RemotePrintJobChild(); + + void ActorDestroy(ActorDestroyReason aWhy) final; + + nsresult InitializePrint(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage); + + bool RecvPrintInitializationResult(const nsresult& aRv) final; + + void ProcessPage(const nsCString& aPageFileName); + + bool RecvPageProcessed() final; + + bool RecvAbortPrint(const nsresult& aRv) final; + + void SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer); + + void SetPrintEngine(nsPrintEngine* aPrintEngine); + +private: + ~RemotePrintJobChild() final; + + bool mPrintInitialized = false; + nsresult mInitializationResult = NS_OK; + RefPtr<nsPagePrintTimer> mPagePrintTimer; + RefPtr<nsPrintEngine> mPrintEngine; +}; + +} // namespace layout +} // namespace mozilla + +#endif // mozilla_layout_RemotePrintJobChild_h diff --git a/layout/printing/ipc/RemotePrintJobParent.cpp b/layout/printing/ipc/RemotePrintJobParent.cpp new file mode 100644 index 000000000..2f4dbd56e --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobParent.cpp @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemotePrintJobParent.h" + +#include <fstream> + +#include "gfxContext.h" +#include "mozilla/Attributes.h" +#include "mozilla/Unused.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsComponentManagerUtils.h" +#include "nsDirectoryServiceUtils.h" +#include "nsDeviceContext.h" +#include "nsIDeviceContextSpec.h" +#include "nsIPrintSettings.h" +#include "nsIWebProgressListener.h" +#include "PrintTranslator.h" + +namespace mozilla { +namespace layout { + +RemotePrintJobParent::RemotePrintJobParent(nsIPrintSettings* aPrintSettings) + : mPrintSettings(aPrintSettings) +{ + MOZ_COUNT_CTOR(RemotePrintJobParent); +} + +bool +RemotePrintJobParent::RecvInitializePrint(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage) +{ + nsresult rv = InitializePrintDevice(aDocumentTitle, aPrintToFile, aStartPage, + aEndPage); + if (NS_FAILED(rv)) { + Unused << SendPrintInitializationResult(rv); + Unused << Send__delete__(this); + return true; + } + + mPrintTranslator.reset(new PrintTranslator(mPrintDeviceContext)); + Unused << SendPrintInitializationResult(NS_OK); + + return true; +} + +nsresult +RemotePrintJobParent::InitializePrintDevice(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage) +{ + nsresult rv; + nsCOMPtr<nsIDeviceContextSpec> deviceContextSpec = + do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = deviceContextSpec->Init(nullptr, mPrintSettings, false); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mPrintDeviceContext = new nsDeviceContext(); + rv = mPrintDeviceContext->InitForPrinting(deviceContextSpec); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = mPrintDeviceContext->BeginDocument(aDocumentTitle, aPrintToFile, + aStartPage, aEndPage); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +bool +RemotePrintJobParent::RecvProcessPage(const nsCString& aPageFileName) +{ + nsresult rv = PrintPage(aPageFileName); + + if (NS_FAILED(rv)) { + Unused << SendAbortPrint(rv); + } else { + Unused << SendPageProcessed(); + } + + return true; +} + +nsresult +RemotePrintJobParent::PrintPage(const nsCString& aPageFileName) +{ + MOZ_ASSERT(mPrintDeviceContext); + + nsresult rv = mPrintDeviceContext->BeginPage(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr<nsIFile> recordingFile; + rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR, + getter_AddRefs(recordingFile)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = recordingFile->AppendNative(aPageFileName); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsAutoCString recordingPath; + rv = recordingFile->GetNativePath(recordingPath); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + std::ifstream recording(recordingPath.get(), std::ifstream::binary); + if (!mPrintTranslator->TranslateRecording(recording)) { + return NS_ERROR_FAILURE; + } + + rv = mPrintDeviceContext->EndPage(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + recording.close(); + rv = recordingFile->Remove(/* recursive= */ false); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +bool +RemotePrintJobParent::RecvFinalizePrint() +{ + // EndDocument is sometimes called in the child even when BeginDocument has + // not been called. See bug 1223332. + if (mPrintDeviceContext) { + DebugOnly<nsresult> rv = mPrintDeviceContext->EndDocument(); + + // Too late to abort the child just log. + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EndDocument failed"); + } + + + Unused << Send__delete__(this); + return true; +} + +bool +RemotePrintJobParent::RecvAbortPrint(const nsresult& aRv) +{ + if (mPrintDeviceContext) { + Unused << mPrintDeviceContext->AbortDocument(); + } + + Unused << Send__delete__(this); + return true; +} + +bool +RemotePrintJobParent::RecvStateChange(const long& aStateFlags, + const nsresult& aStatus) +{ + uint32_t numberOfListeners = mPrintProgressListeners.Length(); + for (uint32_t i = 0; i < numberOfListeners; ++i) { + nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i); + listener->OnStateChange(nullptr, nullptr, aStateFlags, aStatus); + } + + return true; +} + +bool +RemotePrintJobParent::RecvProgressChange(const long& aCurSelfProgress, + const long& aMaxSelfProgress, + const long& aCurTotalProgress, + const long& aMaxTotalProgress) +{ + uint32_t numberOfListeners = mPrintProgressListeners.Length(); + for (uint32_t i = 0; i < numberOfListeners; ++i) { + nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i); + listener->OnProgressChange(nullptr, nullptr, + aCurSelfProgress, aMaxSelfProgress, + aCurTotalProgress, aMaxTotalProgress); + } + + return true; +} + +bool +RemotePrintJobParent::RecvStatusChange(const nsresult& aStatus) +{ + uint32_t numberOfListeners = mPrintProgressListeners.Length(); + for (uint32_t i = 0; i < numberOfListeners; ++i) { + nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i); + listener->OnStatusChange(nullptr, nullptr, aStatus, nullptr); + } + + return true; +} + +void +RemotePrintJobParent::RegisterListener(nsIWebProgressListener* aListener) +{ + MOZ_ASSERT(aListener); + + mPrintProgressListeners.AppendElement(aListener); +} + +already_AddRefed<nsIPrintSettings> +RemotePrintJobParent::GetPrintSettings() +{ + nsCOMPtr<nsIPrintSettings> printSettings = mPrintSettings; + return printSettings.forget(); +} + +RemotePrintJobParent::~RemotePrintJobParent() +{ + MOZ_COUNT_DTOR(RemotePrintJobParent); +} + +void +RemotePrintJobParent::ActorDestroy(ActorDestroyReason aWhy) +{ +} + +} // namespace layout +} // namespace mozilla + + diff --git a/layout/printing/ipc/RemotePrintJobParent.h b/layout/printing/ipc/RemotePrintJobParent.h new file mode 100644 index 000000000..a96cc7eaa --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobParent.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layout_RemotePrintJobParent_h +#define mozilla_layout_RemotePrintJobParent_h + +#include "mozilla/layout/PRemotePrintJobParent.h" + +#include "nsCOMArray.h" +#include "nsCOMPtr.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" + +class nsDeviceContext; +class nsIPrintSettings; +class nsIWebProgressListener; +class PrintTranslator; + +namespace mozilla { +namespace layout { + +class RemotePrintJobParent final : public PRemotePrintJobParent +{ +public: + explicit RemotePrintJobParent(nsIPrintSettings* aPrintSettings); + + void ActorDestroy(ActorDestroyReason aWhy) final; + + bool RecvInitializePrint(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage) final; + + bool RecvProcessPage(const nsCString& aPageFileName) final; + + bool RecvFinalizePrint() final; + + bool RecvAbortPrint(const nsresult& aRv) final; + + bool RecvStateChange(const long& aStateFlags, + const nsresult& aStatus) final; + + bool RecvProgressChange(const long& aCurSelfProgress, + const long& aMaxSelfProgress, + const long& aCurTotalProgress, + const long& aMaxTotalProgress) final; + + bool RecvStatusChange(const nsresult& aStatus) final; + + /** + * Register a progress listener to receive print progress updates. + * + * @param aListener the progress listener to register. Must not be null. + */ + void RegisterListener(nsIWebProgressListener* aListener); + + /** + * @return the print settings for this remote print job. + */ + already_AddRefed<nsIPrintSettings> GetPrintSettings(); + +private: + ~RemotePrintJobParent() final; + + nsresult InitializePrintDevice(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage); + + nsresult PrintPage(const nsCString& aPageFileName); + + nsCOMPtr<nsIPrintSettings> mPrintSettings; + RefPtr<nsDeviceContext> mPrintDeviceContext; + UniquePtr<PrintTranslator> mPrintTranslator; + nsCOMArray<nsIWebProgressListener> mPrintProgressListeners; +}; + +} // namespace layout +} // namespace mozilla + +#endif // mozilla_layout_RemotePrintJobParent_h |