diff options
Diffstat (limited to '')
-rw-r--r-- | widget/nsDeviceContextSpecProxy.cpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/widget/nsDeviceContextSpecProxy.cpp b/widget/nsDeviceContextSpecProxy.cpp new file mode 100644 index 0000000000..17a0664ede --- /dev/null +++ b/widget/nsDeviceContextSpecProxy.cpp @@ -0,0 +1,164 @@ +/* -*- 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 "nsDeviceContextSpecProxy.h" + +#include "gfxASurface.h" +#include "gfxPlatform.h" +#include "mozilla/gfx/DrawEventRecorder.h" +#include "mozilla/gfx/PrintTargetThebes.h" +#include "mozilla/layout/RemotePrintJobChild.h" +#include "mozilla/RefPtr.h" +#include "mozilla/Unused.h" +#include "nsComponentManagerUtils.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsDirectoryServiceUtils.h" +#include "nsIPrintSettings.h" +#include "private/pprio.h" + +using mozilla::Unused; + +using namespace mozilla; +using namespace mozilla::gfx; + +NS_IMPL_ISUPPORTS(nsDeviceContextSpecProxy, nsIDeviceContextSpec) + +nsDeviceContextSpecProxy::nsDeviceContextSpecProxy( + RemotePrintJobChild* aRemotePrintJob) + : mRemotePrintJob(aRemotePrintJob) {} +nsDeviceContextSpecProxy::~nsDeviceContextSpecProxy() = default; + +NS_IMETHODIMP +nsDeviceContextSpecProxy::Init(nsIPrintSettings* aPrintSettings, + bool aIsPrintPreview) { + mPrintSettings = aPrintSettings; + + if (aIsPrintPreview) { + return NS_OK; + } + + if (!mRemotePrintJob) { + NS_WARNING("We can't print via the parent without a RemotePrintJobChild."); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +already_AddRefed<PrintTarget> nsDeviceContextSpecProxy::MakePrintTarget() { + double width, height; + mPrintSettings->GetEffectiveSheetSize(&width, &height); + if (width <= 0 || height <= 0) { + return nullptr; + } + + // convert twips to points + width /= TWIPS_PER_POINT_FLOAT; + height /= TWIPS_PER_POINT_FLOAT; + + RefPtr<gfxASurface> surface = + gfxPlatform::GetPlatform()->CreateOffscreenSurface( + mozilla::gfx::IntSize::Ceil(width, height), + mozilla::gfx::SurfaceFormat::A8R8G8B8_UINT32); + if (!surface) { + return nullptr; + } + + // The type of PrintTarget that we return here shouldn't really matter since + // our implementation of GetDrawEventRecorder returns an object, which means + // the DrawTarget returned by the PrintTarget will be a + // DrawTargetWrapAndRecord. The recording will be serialized and sent over to + // the parent process where PrintTranslator::TranslateRecording will call + // MakePrintTarget (indirectly via PrintTranslator::CreateDrawTarget) on + // whatever type of nsIDeviceContextSpecProxy is created for the platform that + // we are running on. It is that DrawTarget that the recording will be + // replayed on to print. + // XXX(jwatt): The above isn't quite true. We do want to use a + // PrintTargetRecording here, but we can't until bug 1280324 is figured out + // and fixed otherwise we will cause bug 1280181 to happen again. + RefPtr<PrintTarget> target = PrintTargetThebes::CreateOrNull(surface); + + return target.forget(); +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::GetDrawEventRecorder( + mozilla::gfx::DrawEventRecorder** aDrawEventRecorder) { + MOZ_ASSERT(aDrawEventRecorder); + RefPtr<mozilla::gfx::DrawEventRecorder> result = mRecorder; + result.forget(aDrawEventRecorder); + return NS_OK; +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::BeginDocument(const nsAString& aTitle, + const nsAString& aPrintToFileName, + int32_t aStartPage, int32_t aEndPage) { + if (!mRemotePrintJob || mRemotePrintJob->IsDestroyed()) { + mRemotePrintJob = nullptr; + return NS_ERROR_NOT_AVAILABLE; + } + + mRecorder = new mozilla::layout::DrawEventRecorderPRFileDesc(); + nsresult rv = + mRemotePrintJob->InitializePrint(nsString(aTitle), aStartPage, aEndPage); + if (NS_FAILED(rv)) { + // The parent process will send a 'delete' message to tell this process to + // delete our RemotePrintJobChild. As soon as we return to the event loop + // and evaluate that message we will crash if we try to access + // mRemotePrintJob. We must not try to use it again. + mRemotePrintJob = nullptr; + } + return rv; +} + +RefPtr<mozilla::gfx::PrintEndDocumentPromise> +nsDeviceContextSpecProxy::EndDocument() { + if (!mRemotePrintJob || mRemotePrintJob->IsDestroyed()) { + mRemotePrintJob = nullptr; + return mozilla::gfx::PrintEndDocumentPromise::CreateAndReject( + NS_ERROR_NOT_AVAILABLE, __func__); + } + + Unused << mRemotePrintJob->SendFinalizePrint(); + + if (mRecorder) { + MOZ_ASSERT(!mRecorder->IsOpen()); + mRecorder->DetachResources(); + mRecorder = nullptr; + } + + return mozilla::gfx::PrintEndDocumentPromise::CreateAndResolve(true, + __func__); +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::BeginPage(const IntSize& aSizeInPoints) { + if (!mRemotePrintJob || mRemotePrintJob->IsDestroyed()) { + mRemotePrintJob = nullptr; + return NS_ERROR_NOT_AVAILABLE; + } + + mRecorder->OpenFD(mRemotePrintJob->GetNextPageFD()); + mCurrentPageSizeInPoints = aSizeInPoints; + + return NS_OK; +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::EndPage() { + if (!mRemotePrintJob || mRemotePrintJob->IsDestroyed()) { + mRemotePrintJob = nullptr; + return NS_ERROR_NOT_AVAILABLE; + } + + // Send the page recording to the parent. + mRecorder->Close(); + mRemotePrintJob->ProcessPage(mCurrentPageSizeInPoints, + std::move(mRecorder->TakeDependentSurfaces())); + + return NS_OK; +} |