diff options
Diffstat (limited to 'layout/printing/ipc')
-rw-r--r-- | layout/printing/ipc/PRemotePrintJob.ipdl | 57 | ||||
-rw-r--r-- | layout/printing/ipc/RemotePrintJobChild.cpp | 171 | ||||
-rw-r--r-- | layout/printing/ipc/RemotePrintJobChild.h | 69 | ||||
-rw-r--r-- | layout/printing/ipc/RemotePrintJobParent.cpp | 344 | ||||
-rw-r--r-- | layout/printing/ipc/RemotePrintJobParent.h | 102 |
5 files changed, 743 insertions, 0 deletions
diff --git a/layout/printing/ipc/PRemotePrintJob.ipdl b/layout/printing/ipc/PRemotePrintJob.ipdl new file mode 100644 index 0000000000..50b978cfc7 --- /dev/null +++ b/layout/printing/ipc/PRemotePrintJob.ipdl @@ -0,0 +1,57 @@ +/* -*- 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 PContent; + +namespace mozilla { +namespace layout { + +[ChildImpl=virtual, ParentImpl=virtual] +async protocol PRemotePrintJob +{ + manager PContent; + +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, + int32_t aStartPage, int32_t aEndPage); + + // Translate the page recording writen into |fd| and play back the events to + // the real print device. + async ProcessPage(int32_t aWidthInPoints, int32_t aHeightInPoints, uint64_t[] aDeps); + + // This informs the real print device that we've finished, so it can trigger + // the actual print. + async FinalizePrint(); + + // 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. Includes a file descriptor which the first page + // can be written to. + async PrintInitializationResult(nsresult aRv, FileDescriptor aFd); + + // Inform the child that the latest page has been processed remotely. Includes + // a file descriptor which the next page can be written to. + async PageProcessed(FileDescriptor aFd); + + 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 0000000000..bc92272451 --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobChild.cpp @@ -0,0 +1,171 @@ +/* -*- 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/SpinEventLoopUntil.h" +#include "mozilla/Unused.h" +#include "nsPagePrintTimer.h" +#include "nsPrintJob.h" +#include "private/pprio.h" + +namespace mozilla { +namespace layout { + +NS_IMPL_ISUPPORTS(RemotePrintJobChild, nsIWebProgressListener) + +RemotePrintJobChild::RemotePrintJobChild() = default; + +nsresult RemotePrintJobChild::InitializePrint(const nsString& aDocumentTitle, + 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, aStartPage, aEndPage); + mozilla::SpinEventLoopUntil("RemotePrintJobChild::InitializePrint"_ns, + [&]() { return mPrintInitialized; }); + + return mInitializationResult; +} + +mozilla::ipc::IPCResult RemotePrintJobChild::RecvPrintInitializationResult( + const nsresult& aRv, const mozilla::ipc::FileDescriptor& aFd) { + mPrintInitialized = true; + mInitializationResult = aRv; + if (NS_SUCCEEDED(aRv)) { + SetNextPageFD(aFd); + } + return IPC_OK(); +} + +PRFileDesc* RemotePrintJobChild::GetNextPageFD() { + MOZ_ASSERT(!mDestroyed); + MOZ_ASSERT(mNextPageFD); + PRFileDesc* fd = mNextPageFD; + mNextPageFD = nullptr; + return fd; +} + +void RemotePrintJobChild::SetNextPageFD( + const mozilla::ipc::FileDescriptor& aFd) { + MOZ_ASSERT(!mDestroyed); + auto handle = aFd.ClonePlatformHandle(); + mNextPageFD = PR_ImportFile(PROsfd(handle.release())); +} + +void RemotePrintJobChild::ProcessPage(const IntSize& aSizeInPoints, + nsTArray<uint64_t>&& aDeps) { + MOZ_ASSERT(mPagePrintTimer); + + mPagePrintTimer->WaitForRemotePrint(); + if (!mDestroyed) { + Unused << SendProcessPage(aSizeInPoints.width, aSizeInPoints.height, + std::move(aDeps)); + } +} + +mozilla::ipc::IPCResult RemotePrintJobChild::RecvPageProcessed( + const mozilla::ipc::FileDescriptor& aFd) { + MOZ_ASSERT(mPagePrintTimer); + SetNextPageFD(aFd); + + mPagePrintTimer->RemotePrintFinished(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult RemotePrintJobChild::RecvAbortPrint( + const nsresult& aRv) { + MOZ_ASSERT(mPrintJob); + + mPrintJob->CleanupOnFailure(aRv, true); + return IPC_OK(); +} + +void RemotePrintJobChild::SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer) { + MOZ_ASSERT(!mDestroyed); + MOZ_ASSERT(aPagePrintTimer); + + mPagePrintTimer = aPagePrintTimer; +} + +void RemotePrintJobChild::SetPrintJob(nsPrintJob* aPrintJob) { + MOZ_ASSERT(!mDestroyed); + MOZ_ASSERT(aPrintJob); + + mPrintJob = aPrintJob; +} + +// nsIWebProgressListener + +NS_IMETHODIMP +RemotePrintJobChild::OnStateChange(nsIWebProgress* aProgress, + nsIRequest* aRequest, uint32_t aStateFlags, + nsresult aStatus) { + // `RemotePrintJobParent` emits its own state change events based on its + // own progress & the actor lifecycle, so any forwarded event here would get + // ignored. + return NS_OK; +} + +NS_IMETHODIMP +RemotePrintJobChild::OnProgressChange(nsIWebProgress* aProgress, + nsIRequest* aRequest, + int32_t aCurSelfProgress, + int32_t aMaxSelfProgress, + int32_t aCurTotalProgress, + int32_t aMaxTotalProgress) { + if (!mDestroyed) { + 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) { + if (NS_SUCCEEDED(mInitializationResult) && !mDestroyed) { + Unused << SendStatusChange(aStatus); + } + + return NS_OK; +} + +NS_IMETHODIMP +RemotePrintJobChild::OnSecurityChange(nsIWebProgress* aProgress, + nsIRequest* aRequest, uint32_t aState) { + return NS_OK; +} + +NS_IMETHODIMP +RemotePrintJobChild::OnContentBlockingEvent(nsIWebProgress* aProgress, + nsIRequest* aRequest, + uint32_t aEvent) { + return NS_OK; +} + +// End of nsIWebProgressListener + +RemotePrintJobChild::~RemotePrintJobChild() = default; + +void RemotePrintJobChild::ActorDestroy(ActorDestroyReason aWhy) { + mPagePrintTimer = nullptr; + mPrintJob = nullptr; + + mDestroyed = true; +} + +} // namespace layout +} // namespace mozilla diff --git a/layout/printing/ipc/RemotePrintJobChild.h b/layout/printing/ipc/RemotePrintJobChild.h new file mode 100644 index 0000000000..73f2b5ef9c --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobChild.h @@ -0,0 +1,69 @@ +/* -*- 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 "mozilla/gfx/Point.h" +#include "nsIWebProgressListener.h" + +class nsPagePrintTimer; +class nsPrintJob; + +namespace mozilla { +namespace layout { + +class RemotePrintJobChild final : public PRemotePrintJobChild, + public nsIWebProgressListener { + public: + using IntSize = mozilla::gfx::IntSize; + + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBPROGRESSLISTENER + + RemotePrintJobChild(); + + void ActorDestroy(ActorDestroyReason aWhy) final; + + nsresult InitializePrint(const nsString& aDocumentTitle, + const int32_t& aStartPage, const int32_t& aEndPage); + + mozilla::ipc::IPCResult RecvPrintInitializationResult( + const nsresult& aRv, const FileDescriptor& aFd) final; + + void ProcessPage(const IntSize& aSizeInPoints, nsTArray<uint64_t>&& aDeps); + + mozilla::ipc::IPCResult RecvPageProcessed(const FileDescriptor& aFd) final; + + mozilla::ipc::IPCResult RecvAbortPrint(const nsresult& aRv) final; + + void SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer); + + void SetPrintJob(nsPrintJob* aPrintJob); + + PRFileDesc* GetNextPageFD(); + + [[nodiscard]] bool IsDestroyed() const { return mDestroyed; } + + private: + ~RemotePrintJobChild() final; + void SetNextPageFD(const mozilla::ipc::FileDescriptor& aFd); + + bool mPrintInitialized = false; + bool mDestroyed = false; + nsresult mInitializationResult = NS_OK; + RefPtr<nsPagePrintTimer> mPagePrintTimer; + RefPtr<nsPrintJob> mPrintJob; + PRFileDesc* mNextPageFD = nullptr; +}; + +} // 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 0000000000..4e4e363a8a --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobParent.cpp @@ -0,0 +1,344 @@ +/* -*- 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/ProfilerMarkers.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" +#include "private/pprio.h" +#include "nsAnonymousTemporaryFile.h" + +namespace mozilla::layout { + +RemotePrintJobParent::RemotePrintJobParent(nsIPrintSettings* aPrintSettings) + : mPrintSettings(aPrintSettings), + mIsDoingPrinting(false), + mStatus(NS_ERROR_UNEXPECTED) { + MOZ_COUNT_CTOR(RemotePrintJobParent); +} + +mozilla::ipc::IPCResult RemotePrintJobParent::RecvInitializePrint( + const nsAString& aDocumentTitle, const int32_t& aStartPage, + const int32_t& aEndPage) { + PROFILER_MARKER_TEXT("RemotePrintJobParent", LAYOUT_Printing, {}, + "RemotePrintJobParent::RecvInitializePrint"_ns); + + nsresult rv = InitializePrintDevice(aDocumentTitle, aStartPage, aEndPage); + if (NS_FAILED(rv)) { + Unused << SendPrintInitializationResult(rv, FileDescriptor()); + mStatus = rv; + Unused << Send__delete__(this); + return IPC_OK(); + } + + mPrintTranslator.reset(new PrintTranslator(mPrintDeviceContext)); + FileDescriptor fd; + rv = PrepareNextPageFD(&fd); + if (NS_FAILED(rv)) { + Unused << SendPrintInitializationResult(rv, FileDescriptor()); + mStatus = rv; + Unused << Send__delete__(this); + return IPC_OK(); + } + + Unused << SendPrintInitializationResult(NS_OK, fd); + return IPC_OK(); +} + +nsresult RemotePrintJobParent::InitializePrintDevice( + const nsAString& aDocumentTitle, const int32_t& aStartPage, + const int32_t& aEndPage) { + AUTO_PROFILER_MARKER_TEXT("RemotePrintJobParent", LAYOUT_Printing, {}, + "RemotePrintJobParent::InitializePrintDevice"_ns); + + 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(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; + } + + nsAutoString fileName; + mPrintSettings->GetToFileName(fileName); + + rv = mPrintDeviceContext->BeginDocument(aDocumentTitle, fileName, aStartPage, + aEndPage); + if (NS_FAILED(rv)) { + NS_WARNING_ASSERTION(rv == NS_ERROR_ABORT, + "Failed to initialize print device"); + return rv; + } + + mIsDoingPrinting = true; + + return NS_OK; +} + +nsresult RemotePrintJobParent::PrepareNextPageFD(FileDescriptor* aFd) { + AUTO_PROFILER_MARKER_TEXT("RemotePrintJobParent", LAYOUT_Printing, {}, + "RemotePrintJobParent::PrepareNextPageFD"_ns); + + PRFileDesc* prFd = nullptr; + nsresult rv = NS_OpenAnonymousTemporaryFile(&prFd); + if (NS_FAILED(rv)) { + return rv; + } + *aFd = FileDescriptor( + FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prFd))); + mCurrentPageStream.OpenFD(prFd); + return NS_OK; +} + +mozilla::ipc::IPCResult RemotePrintJobParent::RecvProcessPage( + const int32_t& aWidthInPoints, const int32_t& aHeightInPoints, + nsTArray<uint64_t>&& aDeps) { + PROFILER_MARKER_TEXT("RemotePrintJobParent", LAYOUT_Printing, {}, + "RemotePrintJobParent::RecvProcessPage"_ns); + if (!mCurrentPageStream.IsOpen()) { + Unused << SendAbortPrint(NS_ERROR_FAILURE); + return IPC_OK(); + } + mCurrentPageStream.Seek(0, PR_SEEK_SET); + + gfx::IntSize pageSizeInPoints(aWidthInPoints, aHeightInPoints); + + if (aDeps.IsEmpty()) { + FinishProcessingPage(pageSizeInPoints); + return IPC_OK(); + } + + nsTHashSet<uint64_t> deps; + for (auto i : aDeps) { + deps.Insert(i); + } + + gfx::CrossProcessPaint::Start(std::move(deps)) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [self = RefPtr{this}, pageSizeInPoints]( + gfx::CrossProcessPaint::ResolvedFragmentMap&& aFragments) { + self->FinishProcessingPage(pageSizeInPoints, &aFragments); + }, + [self = RefPtr{this}, pageSizeInPoints](const nsresult& aRv) { + self->FinishProcessingPage(pageSizeInPoints); + }); + + return IPC_OK(); +} + +void RemotePrintJobParent::FinishProcessingPage( + const gfx::IntSize& aSizeInPoints, + gfx::CrossProcessPaint::ResolvedFragmentMap* aFragments) { + nsresult rv = PrintPage(aSizeInPoints, mCurrentPageStream, aFragments); + + mCurrentPageStream.Close(); + + PageDone(rv); +} + +nsresult RemotePrintJobParent::PrintPage( + const gfx::IntSize& aSizeInPoints, PRFileDescStream& aRecording, + gfx::CrossProcessPaint::ResolvedFragmentMap* aFragments) { + MOZ_ASSERT(mPrintDeviceContext); + AUTO_PROFILER_MARKER_TEXT("RemotePrintJobParent", LAYOUT_Printing, {}, + "RemotePrintJobParent::PrintPage"_ns); + + nsresult rv = mPrintDeviceContext->BeginPage(aSizeInPoints); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + if (aFragments) { + mPrintTranslator->SetDependentSurfaces(aFragments); + } + if (!mPrintTranslator->TranslateRecording(aRecording)) { + mPrintTranslator->SetDependentSurfaces(nullptr); + return NS_ERROR_FAILURE; + } + mPrintTranslator->SetDependentSurfaces(nullptr); + + rv = mPrintDeviceContext->EndPage(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +void RemotePrintJobParent::PageDone(nsresult aResult) { + MOZ_ASSERT(mIsDoingPrinting); + + if (NS_FAILED(aResult)) { + Unused << SendAbortPrint(aResult); + } else { + FileDescriptor fd; + aResult = PrepareNextPageFD(&fd); + if (NS_FAILED(aResult)) { + Unused << SendAbortPrint(aResult); + } + + Unused << SendPageProcessed(fd); + } +} + +static void NotifyStatusChange( + const nsCOMArray<nsIWebProgressListener>& aListeners, nsresult aStatus) { + uint32_t numberOfListeners = aListeners.Length(); + for (uint32_t i = 0; i < numberOfListeners; ++i) { + nsIWebProgressListener* listener = aListeners[static_cast<int32_t>(i)]; + listener->OnStatusChange(nullptr, nullptr, aStatus, nullptr); + } +} + +static void NotifyStateChange( + const nsCOMArray<nsIWebProgressListener>& aListeners, long aStateFlags, + nsresult aStatus) { + uint32_t numberOfListeners = aListeners.Length(); + for (uint32_t i = 0; i < numberOfListeners; ++i) { + nsIWebProgressListener* listener = aListeners[static_cast<int32_t>(i)]; + listener->OnStateChange(nullptr, nullptr, aStateFlags, aStatus); + } +} + +static void Cleanup(const nsCOMArray<nsIWebProgressListener>& aListeners, + RefPtr<nsDeviceContext>& aAbortContext, + const bool aPrintingInterrupted, const nsresult aResult) { + auto result = aResult; + if (MOZ_UNLIKELY(aPrintingInterrupted && NS_SUCCEEDED(result))) { + result = NS_ERROR_UNEXPECTED; + } + if (NS_FAILED(result)) { + NotifyStatusChange(aListeners, result); + } + if (aPrintingInterrupted && aAbortContext) { + // Abort any started print. + Unused << aAbortContext->AbortDocument(); + } + // However the print went, let the listeners know that we're done. + NotifyStateChange(aListeners, + nsIWebProgressListener::STATE_STOP | + nsIWebProgressListener::STATE_IS_DOCUMENT, + result); +} + +mozilla::ipc::IPCResult RemotePrintJobParent::RecvFinalizePrint() { + PROFILER_MARKER_TEXT("RemotePrintJobParent", LAYOUT_Printing, {}, + "RemotePrintJobParent::RecvFinalizePrint"_ns); + + // EndDocument is sometimes called in the child even when BeginDocument has + // not been called. See bug 1223332. + if (mPrintDeviceContext) { + mPrintDeviceContext->EndDocument()->Then( + GetMainThreadSerialEventTarget(), __func__, + [listeners = std::move(mPrintProgressListeners)]( + const mozilla::gfx::PrintEndDocumentPromise::ResolveOrRejectValue& + aResult) { + // Printing isn't interrupted, so we don't need the device context + // here. + RefPtr<nsDeviceContext> empty; + if (aResult.IsResolve()) { + Cleanup(listeners, empty, /* aPrintingInterrupted = */ false, + NS_OK); + } else { + Cleanup(listeners, empty, /* aPrintingInterrupted = */ false, + aResult.RejectValue()); + } + }); + mStatus = NS_OK; + } + + mIsDoingPrinting = false; + + Unused << Send__delete__(this); + return IPC_OK(); +} + +mozilla::ipc::IPCResult RemotePrintJobParent::RecvAbortPrint( + const nsresult& aRv) { + PROFILER_MARKER_TEXT("RemotePrintJobParent", LAYOUT_Printing, {}, + "RemotePrintJobParent::RecvAbortPrint"_ns); + + // Leave the cleanup to `ActorDestroy()`. + Unused << Send__delete__(this); + return IPC_OK(); +} + +mozilla::ipc::IPCResult RemotePrintJobParent::RecvProgressChange( + const long& aCurSelfProgress, const long& aMaxSelfProgress, + const long& aCurTotalProgress, const long& aMaxTotalProgress) { + PROFILER_MARKER_TEXT("RemotePrintJobParent", LAYOUT_Printing, {}, + "RemotePrintJobParent::RecvProgressChange"_ns); + // Our progress follows that of `RemotePrintJobChild` closely enough - forward + // it instead of keeping more state variables here. + for (auto* listener : mPrintProgressListeners) { + listener->OnProgressChange(nullptr, nullptr, aCurSelfProgress, + aMaxSelfProgress, aCurTotalProgress, + aMaxTotalProgress); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult RemotePrintJobParent::RecvStatusChange( + const nsresult& aStatus) { + PROFILER_MARKER_TEXT("RemotePrintJobParent", LAYOUT_Printing, {}, + "RemotePrintJobParent::RecvProgressChange"_ns); + if (NS_FAILED(aStatus)) { + // Remember the failure status for cleanup to forward to listeners. + mStatus = aStatus; + } + + return IPC_OK(); +} + +void RemotePrintJobParent::RegisterListener(nsIWebProgressListener* aListener) { + MOZ_ASSERT(aListener); + + // Our listener is a Promise created by CanonicalBrowsingContext::Print + 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) { + if (MOZ_UNLIKELY(mIsDoingPrinting && NS_SUCCEEDED(mStatus))) { + mStatus = NS_ERROR_UNEXPECTED; + } + Cleanup(mPrintProgressListeners, mPrintDeviceContext, mIsDoingPrinting, + mStatus); + // At any rate, this actor is done and cleaned up. + mIsDoingPrinting = false; +} + +} // namespace mozilla::layout diff --git a/layout/printing/ipc/RemotePrintJobParent.h b/layout/printing/ipc/RemotePrintJobParent.h new file mode 100644 index 0000000000..2f80553183 --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobParent.h @@ -0,0 +1,102 @@ +/* -*- 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 "mozilla/layout/printing/DrawEventRecorder.h" + +#include "nsCOMArray.h" +#include "nsCOMPtr.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/gfx/Point.h" +#include "mozilla/gfx/RecordedEvent.h" +#include "mozilla/gfx/CrossProcessPaint.h" + +class nsDeviceContext; +class nsIPrintSettings; +class nsIWebProgressListener; + +namespace mozilla { +namespace layout { + +class PrintTranslator; + +class RemotePrintJobParent final : public PRemotePrintJobParent { + public: + NS_INLINE_DECL_REFCOUNTING(RemotePrintJobParent); + + explicit RemotePrintJobParent(nsIPrintSettings* aPrintSettings); + + void ActorDestroy(ActorDestroyReason aWhy) final; + + mozilla::ipc::IPCResult RecvInitializePrint(const nsAString& aDocumentTitle, + const int32_t& aStartPage, + const int32_t& aEndPage) final; + + mozilla::ipc::IPCResult RecvProcessPage(const int32_t& aWidthInPoints, + const int32_t& aHeightInPoints, + nsTArray<uint64_t>&& aDeps) final; + + mozilla::ipc::IPCResult RecvFinalizePrint() final; + + mozilla::ipc::IPCResult RecvAbortPrint(const nsresult& aRv) final; + + mozilla::ipc::IPCResult RecvProgressChange( + const long& aCurSelfProgress, const long& aMaxSelfProgress, + const long& aCurTotalProgress, const long& aMaxTotalProgress) final; + + mozilla::ipc::IPCResult 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 nsAString& aDocumentTitle, + const int32_t& aStartPage, + const int32_t& aEndPage); + + nsresult PrepareNextPageFD(FileDescriptor* aFd); + + nsresult PrintPage( + const gfx::IntSize& aSizeInPoints, PRFileDescStream& aRecording, + gfx::CrossProcessPaint::ResolvedFragmentMap* aFragments = nullptr); + void FinishProcessingPage( + const gfx::IntSize& aSizeInPoints, + gfx::CrossProcessPaint::ResolvedFragmentMap* aFragments = nullptr); + + /** + * Called to notify our corresponding RemotePrintJobChild once we've + * finished printing a page. + */ + void PageDone(nsresult aResult); + + nsCOMPtr<nsIPrintSettings> mPrintSettings; + RefPtr<nsDeviceContext> mPrintDeviceContext; + UniquePtr<PrintTranslator> mPrintTranslator; + nsCOMArray<nsIWebProgressListener> mPrintProgressListeners; + PRFileDescStream mCurrentPageStream; + bool mIsDoingPrinting; + nsresult mStatus; +}; + +} // namespace layout +} // namespace mozilla + +#endif // mozilla_layout_RemotePrintJobParent_h |