Line data Source code
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/. */
6 :
7 : #include "nsDeviceContextSpecProxy.h"
8 :
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 "nsIUUIDGenerator.h"
22 :
23 : using mozilla::Unused;
24 :
25 : using namespace mozilla;
26 : using namespace mozilla::gfx;
27 :
28 0 : NS_IMPL_ISUPPORTS(nsDeviceContextSpecProxy, nsIDeviceContextSpec)
29 :
30 : NS_IMETHODIMP
31 0 : nsDeviceContextSpecProxy::Init(nsIWidget* aWidget,
32 : nsIPrintSettings* aPrintSettings,
33 : bool aIsPrintPreview)
34 : {
35 : nsresult rv;
36 : mRealDeviceContextSpec =
37 0 : do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv);
38 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
39 0 : return rv;
40 : }
41 :
42 0 : mRealDeviceContextSpec->Init(nullptr, aPrintSettings, aIsPrintPreview);
43 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
44 0 : mRealDeviceContextSpec = nullptr;
45 0 : return rv;
46 : }
47 :
48 0 : mPrintSettings = aPrintSettings;
49 :
50 0 : if (aIsPrintPreview) {
51 0 : return NS_OK;
52 : }
53 :
54 : // nsIPrintSettings only has a weak reference to nsIPrintSession, so we hold
55 : // it to make sure it's available for the lifetime of the print.
56 0 : rv = mPrintSettings->GetPrintSession(getter_AddRefs(mPrintSession));
57 0 : if (NS_FAILED(rv) || !mPrintSession) {
58 0 : NS_WARNING("We can't print via the parent without an nsIPrintSession.");
59 0 : return NS_ERROR_FAILURE;
60 : }
61 :
62 0 : rv = mPrintSession->GetRemotePrintJob(getter_AddRefs(mRemotePrintJob));
63 0 : if (NS_FAILED(rv) || !mRemotePrintJob) {
64 0 : NS_WARNING("We can't print via the parent without a RemotePrintJobChild.");
65 0 : return NS_ERROR_FAILURE;
66 : }
67 :
68 0 : rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
69 0 : getter_AddRefs(mRecordingDir));
70 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
71 0 : return rv;
72 : }
73 :
74 0 : mUuidGenerator = do_GetService("@mozilla.org/uuid-generator;1", &rv);
75 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
76 0 : return rv;
77 : }
78 :
79 0 : return NS_OK;
80 : }
81 :
82 : already_AddRefed<PrintTarget>
83 0 : nsDeviceContextSpecProxy::MakePrintTarget()
84 : {
85 0 : MOZ_ASSERT(mRealDeviceContextSpec);
86 :
87 : double width, height;
88 0 : nsresult rv = mPrintSettings->GetEffectivePageSize(&width, &height);
89 0 : if (NS_WARN_IF(NS_FAILED(rv)) || width <= 0 || height <= 0) {
90 0 : return nullptr;
91 : }
92 :
93 : // convert twips to points
94 0 : width /= TWIPS_PER_POINT_FLOAT;
95 0 : height /= TWIPS_PER_POINT_FLOAT;
96 :
97 0 : RefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
98 0 : CreateOffscreenSurface(mozilla::gfx::IntSize::Truncate(width, height),
99 0 : mozilla::gfx::SurfaceFormat::A8R8G8B8_UINT32);
100 0 : if (!surface) {
101 0 : return nullptr;
102 : }
103 :
104 : // The type of PrintTarget that we return here shouldn't really matter since
105 : // our implementation of GetDrawEventRecorder returns an object, which means
106 : // the DrawTarget returned by the PrintTarget will be a DrawTargetWrapAndRecord.
107 : // The recording will be serialized and sent over to the parent process where
108 : // PrintTranslator::TranslateRecording will call MakePrintTarget (indirectly
109 : // via PrintTranslator::CreateDrawTarget) on whatever type of
110 : // nsIDeviceContextSpecProxy is created for the platform that we are running
111 : // on. It is that DrawTarget that the recording will be replayed on to
112 : // print.
113 : // XXX(jwatt): The above isn't quite true. We do want to use a
114 : // PrintTargetRecording here, but we can't until bug 1280324 is figured out
115 : // and fixed otherwise we will cause bug 1280181 to happen again.
116 0 : RefPtr<PrintTarget> target = PrintTargetThebes::CreateOrNull(surface);
117 :
118 0 : return target.forget();
119 : }
120 :
121 : NS_IMETHODIMP
122 0 : nsDeviceContextSpecProxy::GetDrawEventRecorder(mozilla::gfx::DrawEventRecorder** aDrawEventRecorder)
123 : {
124 0 : MOZ_ASSERT(aDrawEventRecorder);
125 0 : RefPtr<mozilla::gfx::DrawEventRecorder> result = mRecorder;
126 0 : result.forget(aDrawEventRecorder);
127 0 : return NS_OK;
128 : }
129 :
130 : float
131 0 : nsDeviceContextSpecProxy::GetDPI()
132 : {
133 0 : MOZ_ASSERT(mRealDeviceContextSpec);
134 :
135 0 : return mRealDeviceContextSpec->GetDPI();
136 : }
137 :
138 : float
139 0 : nsDeviceContextSpecProxy::GetPrintingScale()
140 : {
141 0 : MOZ_ASSERT(mRealDeviceContextSpec);
142 :
143 0 : return mRealDeviceContextSpec->GetPrintingScale();
144 : }
145 :
146 : nsresult
147 0 : nsDeviceContextSpecProxy::CreateUniqueTempPath(nsACString& aFilePath)
148 : {
149 0 : MOZ_ASSERT(mRecordingDir);
150 0 : MOZ_ASSERT(mUuidGenerator);
151 :
152 : nsID uuid;
153 0 : nsresult rv = mUuidGenerator->GenerateUUIDInPlace(&uuid);
154 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
155 0 : return rv;
156 : }
157 :
158 : char uuidChars[NSID_LENGTH];
159 0 : uuid.ToProvidedString(uuidChars);
160 0 : mRecordingFileName.AssignASCII(uuidChars);
161 :
162 0 : nsCOMPtr<nsIFile> recordingFile;
163 0 : rv = mRecordingDir->Clone(getter_AddRefs(recordingFile));
164 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
165 0 : return rv;
166 : }
167 :
168 0 : rv = recordingFile->AppendNative(mRecordingFileName);
169 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
170 0 : return rv;
171 : }
172 :
173 0 : return recordingFile->GetNativePath(aFilePath);
174 : }
175 :
176 : NS_IMETHODIMP
177 0 : nsDeviceContextSpecProxy::BeginDocument(const nsAString& aTitle,
178 : const nsAString& aPrintToFileName,
179 : int32_t aStartPage, int32_t aEndPage)
180 : {
181 0 : nsAutoCString recordingPath;
182 0 : nsresult rv = CreateUniqueTempPath(recordingPath);
183 0 : if (NS_FAILED(rv)) {
184 0 : return rv;
185 : }
186 :
187 0 : mRecorder = new mozilla::gfx::DrawEventRecorderFile(recordingPath.get());
188 0 : return mRemotePrintJob->InitializePrint(nsString(aTitle),
189 0 : nsString(aPrintToFileName),
190 0 : aStartPage, aEndPage);
191 : }
192 :
193 : NS_IMETHODIMP
194 0 : nsDeviceContextSpecProxy::EndDocument()
195 : {
196 0 : Unused << mRemotePrintJob->SendFinalizePrint();
197 0 : return NS_OK;
198 : }
199 :
200 : NS_IMETHODIMP
201 0 : nsDeviceContextSpecProxy::AbortDocument()
202 : {
203 0 : Unused << mRemotePrintJob->SendAbortPrint(NS_OK);
204 0 : return NS_OK;
205 : }
206 :
207 : NS_IMETHODIMP
208 0 : nsDeviceContextSpecProxy::BeginPage()
209 : {
210 : // Reopen the file, if necessary, ready for the next page.
211 0 : if (!mRecorder->IsOpen()) {
212 0 : nsAutoCString recordingPath;
213 0 : nsresult rv = CreateUniqueTempPath(recordingPath);
214 0 : if (NS_FAILED(rv)) {
215 0 : return rv;
216 : }
217 :
218 0 : mRecorder->OpenNew(recordingPath.get());
219 : }
220 :
221 0 : return NS_OK;
222 : }
223 :
224 : NS_IMETHODIMP
225 0 : nsDeviceContextSpecProxy::EndPage()
226 : {
227 : // Send the page recording to the parent.
228 0 : mRecorder->Close();
229 0 : mRemotePrintJob->ProcessPage(mRecordingFileName);
230 :
231 0 : return NS_OK;
232 : }
|