1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsDeviceContextSpecProxy.h"
9 #include "gfxASurface.h"
10 #include "gfxPlatform.h"
11 #include "mozilla/gfx/DrawEventRecorder.h"
12 #include "mozilla/gfx/PrintTargetThebes.h"
13 #include "mozilla/layout/RemotePrintJobChild.h"
14 #include "mozilla/RefPtr.h"
15 #include "mozilla/Unused.h"
16 #include "nsComponentManagerUtils.h"
17 #include "nsAppDirectoryServiceDefs.h"
18 #include "nsDirectoryServiceUtils.h"
19 #include "nsIPrintSession.h"
20 #include "nsIPrintSettings.h"
21 #include "private/pprio.h"
23 using mozilla::Unused
;
25 using namespace mozilla
;
26 using namespace mozilla::gfx
;
28 NS_IMPL_ISUPPORTS(nsDeviceContextSpecProxy
, nsIDeviceContextSpec
)
30 nsDeviceContextSpecProxy::nsDeviceContextSpecProxy() = default;
31 nsDeviceContextSpecProxy::~nsDeviceContextSpecProxy() = default;
34 nsDeviceContextSpecProxy::Init(nsIWidget
* aWidget
,
35 nsIPrintSettings
* aPrintSettings
,
36 bool aIsPrintPreview
) {
38 mRealDeviceContextSpec
=
39 do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv
);
40 if (NS_WARN_IF(NS_FAILED(rv
))) {
44 mRealDeviceContextSpec
->Init(nullptr, aPrintSettings
, aIsPrintPreview
);
45 if (NS_WARN_IF(NS_FAILED(rv
))) {
46 mRealDeviceContextSpec
= nullptr;
50 mPrintSettings
= aPrintSettings
;
52 if (aIsPrintPreview
) {
56 // nsIPrintSettings only has a weak reference to nsIPrintSession, so we hold
57 // it to make sure it's available for the lifetime of the print.
58 rv
= mPrintSettings
->GetPrintSession(getter_AddRefs(mPrintSession
));
59 if (NS_FAILED(rv
) || !mPrintSession
) {
60 NS_WARNING("We can't print via the parent without an nsIPrintSession.");
61 return NS_ERROR_FAILURE
;
64 mRemotePrintJob
= mPrintSession
->GetRemotePrintJob();
65 if (!mRemotePrintJob
) {
66 NS_WARNING("We can't print via the parent without a RemotePrintJobChild.");
67 return NS_ERROR_FAILURE
;
73 already_AddRefed
<PrintTarget
> nsDeviceContextSpecProxy::MakePrintTarget() {
74 MOZ_ASSERT(mRealDeviceContextSpec
);
77 mPrintSettings
->GetEffectiveSheetSize(&width
, &height
);
78 if (width
<= 0 || height
<= 0) {
82 // convert twips to points
83 width
/= TWIPS_PER_POINT_FLOAT
;
84 height
/= TWIPS_PER_POINT_FLOAT
;
86 RefPtr
<gfxASurface
> surface
=
87 gfxPlatform::GetPlatform()->CreateOffscreenSurface(
88 mozilla::gfx::IntSize::Ceil(width
, height
),
89 mozilla::gfx::SurfaceFormat::A8R8G8B8_UINT32
);
94 // The type of PrintTarget that we return here shouldn't really matter since
95 // our implementation of GetDrawEventRecorder returns an object, which means
96 // the DrawTarget returned by the PrintTarget will be a
97 // DrawTargetWrapAndRecord. The recording will be serialized and sent over to
98 // the parent process where PrintTranslator::TranslateRecording will call
99 // MakePrintTarget (indirectly via PrintTranslator::CreateDrawTarget) on
100 // whatever type of nsIDeviceContextSpecProxy is created for the platform that
101 // we are running on. It is that DrawTarget that the recording will be
102 // replayed on to print.
103 // XXX(jwatt): The above isn't quite true. We do want to use a
104 // PrintTargetRecording here, but we can't until bug 1280324 is figured out
105 // and fixed otherwise we will cause bug 1280181 to happen again.
106 RefPtr
<PrintTarget
> target
= PrintTargetThebes::CreateOrNull(surface
);
108 return target
.forget();
112 nsDeviceContextSpecProxy::GetDrawEventRecorder(
113 mozilla::gfx::DrawEventRecorder
** aDrawEventRecorder
) {
114 MOZ_ASSERT(aDrawEventRecorder
);
115 RefPtr
<mozilla::gfx::DrawEventRecorder
> result
= mRecorder
;
116 result
.forget(aDrawEventRecorder
);
120 float nsDeviceContextSpecProxy::GetDPI() {
121 MOZ_ASSERT(mRealDeviceContextSpec
);
123 return mRealDeviceContextSpec
->GetDPI();
126 float nsDeviceContextSpecProxy::GetPrintingScale() {
127 MOZ_ASSERT(mRealDeviceContextSpec
);
129 return mRealDeviceContextSpec
->GetPrintingScale();
132 gfxPoint
nsDeviceContextSpecProxy::GetPrintingTranslate() {
133 MOZ_ASSERT(mRealDeviceContextSpec
);
135 return mRealDeviceContextSpec
->GetPrintingTranslate();
139 nsDeviceContextSpecProxy::BeginDocument(const nsAString
& aTitle
,
140 const nsAString
& aPrintToFileName
,
141 int32_t aStartPage
, int32_t aEndPage
) {
142 if (!mRemotePrintJob
|| mRemotePrintJob
->IsDestroyed()) {
143 mRemotePrintJob
= nullptr;
144 return NS_ERROR_NOT_AVAILABLE
;
147 mRecorder
= new mozilla::layout::DrawEventRecorderPRFileDesc();
148 nsresult rv
= mRemotePrintJob
->InitializePrint(
149 nsString(aTitle
), nsString(aPrintToFileName
), aStartPage
, aEndPage
);
151 // The parent process will send a 'delete' message to tell this process to
152 // delete our RemotePrintJobChild. As soon as we return to the event loop
153 // and evaluate that message we will crash if we try to access
154 // mRemotePrintJob. We must not try to use it again.
155 mRemotePrintJob
= nullptr;
161 nsDeviceContextSpecProxy::EndDocument() {
162 if (!mRemotePrintJob
|| mRemotePrintJob
->IsDestroyed()) {
163 mRemotePrintJob
= nullptr;
164 return NS_ERROR_NOT_AVAILABLE
;
167 Unused
<< mRemotePrintJob
->SendFinalizePrint();
173 nsDeviceContextSpecProxy::AbortDocument() {
174 if (!mRemotePrintJob
|| mRemotePrintJob
->IsDestroyed()) {
175 mRemotePrintJob
= nullptr;
176 return NS_ERROR_NOT_AVAILABLE
;
179 Unused
<< mRemotePrintJob
->SendAbortPrint(NS_OK
);
185 nsDeviceContextSpecProxy::BeginPage() {
186 if (!mRemotePrintJob
|| mRemotePrintJob
->IsDestroyed()) {
187 mRemotePrintJob
= nullptr;
188 return NS_ERROR_NOT_AVAILABLE
;
191 mRecorder
->OpenFD(mRemotePrintJob
->GetNextPageFD());
197 nsDeviceContextSpecProxy::EndPage() {
198 if (!mRemotePrintJob
|| mRemotePrintJob
->IsDestroyed()) {
199 mRemotePrintJob
= nullptr;
200 return NS_ERROR_NOT_AVAILABLE
;
203 // Send the page recording to the parent.
205 mRemotePrintJob
->ProcessPage(std::move(mRecorder
->TakeDependentSurfaces()));