1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Conrad Carlen <ccarlen@netscape.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsPrintSettingsX.h"
40 #include "nsObjCExceptions.h"
41 #include "nsIPrintSessionX.h"
43 #include "nsIPrefService.h"
44 #include "nsIPrefBranch.h"
45 #include "nsServiceManagerUtils.h"
52 // This struct should be represented identically on all architectures, and
53 // there shouldn't be any padding before the data field.
60 #define PRINTING_PREF_BRANCH "print."
61 #define MAC_OS_X_PAGE_SETUP_PREFNAME "macosx.pagesetup-2"
64 // Utility class stack-based handle ownership
68 StHandleOwner(Handle inHandle)
75 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
78 ::DisposeHandle(mHandle);
80 NS_OBJC_END_TRY_ABORT_BLOCK;
83 Handle GetHandle() { return mHandle; }
85 void ClearHandle(Boolean disposeIt = false)
87 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
90 ::DisposeHandle(mHandle);
94 NS_OBJC_END_TRY_ABORT_BLOCK;
102 // Utility class for saving, locking, and restoring handle state.
103 // Ok with null handle.
107 StHandleLocker(Handle theHandle)
110 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
113 mOldHandleState = ::HGetState(mHandle);
117 NS_OBJC_END_TRY_ABORT_BLOCK;
122 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
125 ::HSetState(mHandle, mOldHandleState);
127 NS_OBJC_END_TRY_ABORT_BLOCK;
132 SInt8 mOldHandleState;
136 NS_IMPL_ISUPPORTS_INHERITED1(nsPrintSettingsX, nsPrintSettings, nsIPrintSettingsX)
138 nsPrintSettingsX::nsPrintSettingsX() :
139 mPageFormat(kPMNoPageFormat),
140 mPrintSettings(kPMNoPrintSettings)
145 nsPrintSettingsX::nsPrintSettingsX(const nsPrintSettingsX& src) :
146 mPageFormat(kPMNoPageFormat),
147 mPrintSettings(kPMNoPrintSettings)
153 nsPrintSettingsX::~nsPrintSettingsX()
155 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
157 if (mPageFormat != kPMNoPageFormat) {
158 ::PMRelease(mPageFormat);
159 mPageFormat = kPMNoPageFormat;
161 if (mPrintSettings != kPMNoPrintSettings) {
162 ::PMRelease(mPrintSettings);
163 mPrintSettings = kPMNoPrintSettings;
166 NS_OBJC_END_TRY_ABORT_BLOCK;
170 nsPrintSettingsX& nsPrintSettingsX::operator=(const nsPrintSettingsX& rhs)
172 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
178 nsPrintSettings::operator=(rhs);
182 if (mPageFormat != kPMNoPageFormat) {
183 ::PMRelease(mPageFormat);
184 mPageFormat = kPMNoPageFormat;
186 if (rhs.mPageFormat != kPMNoPageFormat) {
187 PMPageFormat pageFormat;
188 status = ::PMCreatePageFormat(&pageFormat);
189 if (status == noErr) {
190 status = ::PMCopyPageFormat(rhs.mPageFormat, pageFormat);
191 if (status == noErr) {
192 mPageFormat = pageFormat;
193 // NOTE: No need to re-initialize mUnwriteableMargin here (even
194 // though mPageFormat is changing). It'll be copied correctly by
195 // nsPrintSettings::operator=.
197 ::PMRelease(pageFormat);
202 if (mPrintSettings != kPMNoPrintSettings) {
203 ::PMRelease(mPrintSettings);
204 mPrintSettings = kPMNoPrintSettings;
206 if (rhs.mPrintSettings != kPMNoPrintSettings) {
207 PMPrintSettings printSettings;
208 status = ::PMCreatePrintSettings(&printSettings);
209 if (status == noErr) {
210 status = ::PMCopyPrintSettings(rhs.mPrintSettings, printSettings);
212 mPrintSettings = printSettings;
214 ::PMRelease(printSettings);
220 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(*this);
224 nsresult nsPrintSettingsX::Init()
226 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
230 PMPrintSession printSession = NULL;
231 status = ::PMCreateSession(&printSession);
233 if (status == noErr) {
234 // First, create a default page format
235 status = CreateDefaultPageFormat(printSession, mPageFormat);
236 InitUnwriteableMargin();
238 // Then, if no error, create the default print settings
239 if (status == noErr) {
240 status = CreateDefaultPrintSettings(printSession, mPrintSettings);
242 OSStatus tempStatus = ::PMRelease(printSession);
246 return (status == noErr) ? NS_OK : NS_ERROR_FAILURE;
248 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
252 // Should be called whenever mPageFormat changes.
253 NS_IMETHODIMP nsPrintSettingsX::InitUnwriteableMargin()
255 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
257 if (mPageFormat == kPMNoPageFormat)
261 PMPaperMargins paperMargin;
262 ::PMGetPageFormatPaper(mPageFormat, &paper);
263 ::PMPaperGetMargins(paper, &paperMargin);
264 mUnwriteableMargin.top = NS_POINTS_TO_TWIPS(paperMargin.top);
265 mUnwriteableMargin.left = NS_POINTS_TO_TWIPS(paperMargin.left);
266 mUnwriteableMargin.bottom = NS_POINTS_TO_TWIPS(paperMargin.bottom);
267 mUnwriteableMargin.right = NS_POINTS_TO_TWIPS(paperMargin.right);
271 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
275 NS_IMETHODIMP nsPrintSettingsX::GetNativePrintSession(PMPrintSession *aNativePrintSession)
277 NS_ENSURE_ARG_POINTER(aNativePrintSession);
278 *aNativePrintSession = nsnull;
280 nsCOMPtr<nsIPrintSession> printSession;
281 GetPrintSession(getter_AddRefs(printSession));
283 return NS_ERROR_FAILURE;
284 nsCOMPtr<nsIPrintSessionX> printSessionX(do_QueryInterface(printSession));
286 return NS_ERROR_FAILURE;
288 return printSessionX->GetNativeSession(aNativePrintSession);
292 NS_IMETHODIMP nsPrintSettingsX::GetPMPageFormat(PMPageFormat *aPMPageFormat)
294 NS_ENSURE_ARG_POINTER(aPMPageFormat);
295 *aPMPageFormat = kPMNoPageFormat;
296 NS_ENSURE_STATE(mPageFormat != kPMNoPageFormat);
298 *aPMPageFormat = mPageFormat;
299 OSStatus status = noErr;
301 return (status == noErr) ? NS_OK : NS_ERROR_FAILURE;
305 NS_IMETHODIMP nsPrintSettingsX::SetPMPageFormat(PMPageFormat aPMPageFormat)
307 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
309 NS_ENSURE_ARG(aPMPageFormat);
311 OSStatus status = ::PMRetain(aPMPageFormat);
312 if (status == noErr) {
314 status = ::PMRelease(mPageFormat);
315 mPageFormat = aPMPageFormat;
316 InitUnwriteableMargin();
318 return (status == noErr) ? NS_OK : NS_ERROR_FAILURE;
320 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
324 NS_IMETHODIMP nsPrintSettingsX::GetPMPrintSettings(PMPrintSettings *aPMPrintSettings)
326 NS_ENSURE_ARG_POINTER(aPMPrintSettings);
327 *aPMPrintSettings = kPMNoPrintSettings;
328 NS_ENSURE_STATE(mPrintSettings != kPMNoPrintSettings);
330 *aPMPrintSettings = mPrintSettings;
336 NS_IMETHODIMP nsPrintSettingsX::SetPMPrintSettings(PMPrintSettings aPMPrintSettings)
338 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
340 NS_ENSURE_ARG(aPMPrintSettings);
342 OSStatus status = ::PMRetain(aPMPrintSettings);
343 if (status == noErr) {
345 status = ::PMRelease(mPrintSettings);
346 mPrintSettings = aPMPrintSettings;
348 return (status == noErr) ? NS_OK : NS_ERROR_FAILURE;
350 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
354 NS_IMETHODIMP nsPrintSettingsX::ReadPageFormatFromPrefs()
356 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
359 nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
362 nsCOMPtr<nsIPrefBranch> prefBranch;
363 rv = prefService->GetBranch(PRINTING_PREF_BRANCH, getter_AddRefs(prefBranch));
367 nsXPIDLCString encodedData;
368 rv = prefBranch->GetCharPref(MAC_OS_X_PAGE_SETUP_PREFNAME, getter_Copies(encodedData));
373 PRInt32 encodedDataLen = encodedData.Length();
374 FrozenHandle* frozenHandle =
375 (FrozenHandle*)::PL_Base64Decode(encodedData.get(), encodedDataLen, nsnull);
377 return NS_ERROR_FAILURE;
379 PRUint32 handleSize = PR_ntohl(frozenHandle->size);
381 // Ensure that the length reported in the frozen handle agrees with the
382 // amount of decoded data. At most 3 bytes of data map to 4 bytes when
384 PRUint32 maximumDataSize = (encodedDataLen * 3) / 4 - sizeof(FrozenHandle);
385 PRUint32 minimumDataSize = maximumDataSize - 2;
386 if (handleSize > maximumDataSize || handleSize < minimumDataSize) {
388 return NS_ERROR_FAILURE;
391 Handle decodedDataHandle = nsnull;
392 OSErr err = ::PtrToHand(frozenHandle->data, &decodedDataHandle, handleSize);
395 return NS_ERROR_OUT_OF_MEMORY;
397 StHandleOwner handleOwner(decodedDataHandle);
400 PMPageFormat newPageFormat = kPMNoPageFormat;
402 status = ::PMCreatePageFormat(&newPageFormat);
403 if (status == noErr) {
404 status = ::PMUnflattenPageFormat(decodedDataHandle, &newPageFormat);
405 if (status == noErr) {
407 status = ::PMRelease(mPageFormat);
408 mPageFormat = newPageFormat; // PMCreatePageFormat returned it with a refcnt of 1
409 InitUnwriteableMargin();
412 return (status == noErr) ? NS_OK : NS_ERROR_FAILURE;
414 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
418 NS_IMETHODIMP nsPrintSettingsX::WritePageFormatToPrefs()
420 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
422 if (mPageFormat == kPMNoPageFormat)
423 return NS_ERROR_NOT_INITIALIZED;
426 nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
429 nsCOMPtr<nsIPrefBranch> prefBranch;
430 rv = prefService->GetBranch(PRINTING_PREF_BRANCH, getter_AddRefs(prefBranch));
434 Handle pageFormatHandle = nsnull;
435 OSStatus err = ::PMFlattenPageFormat(mPageFormat, &pageFormatHandle);
437 return NS_ERROR_FAILURE;
439 StHandleOwner handleOwner(pageFormatHandle);
440 StHandleLocker handleLocker(pageFormatHandle);
442 // Save the handle in a struct that identifies the data length and
443 // the data itself, and wrap it all up in base64. The length must be
444 // included because PL_DecodeBase64 doesn't return the size of the
445 // decoded data, and the handle will need to be reconstructed later with
447 PRUint32 dataSize = ::GetHandleSize(pageFormatHandle);
448 PRUint32 frozenDataSize = sizeof(FrozenHandle) + dataSize;
449 FrozenHandle* frozenHandle = (FrozenHandle*)malloc(frozenDataSize);
451 return NS_ERROR_OUT_OF_MEMORY;
453 frozenHandle->size = PR_htonl(dataSize);
454 memcpy(&frozenHandle->data, *pageFormatHandle, dataSize);
456 nsXPIDLCString encodedData;
457 encodedData.Adopt(::PL_Base64Encode((char*)frozenHandle, frozenDataSize,
460 if (!encodedData.get())
461 return NS_ERROR_OUT_OF_MEMORY;
463 return prefBranch->SetCharPref(MAC_OS_X_PAGE_SETUP_PREFNAME, encodedData);
465 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
469 nsresult nsPrintSettingsX::_Clone(nsIPrintSettings **_retval)
471 NS_ENSURE_ARG_POINTER(_retval);
474 nsPrintSettingsX *newSettings = new nsPrintSettingsX(*this);
476 return NS_ERROR_FAILURE;
477 *_retval = newSettings;
483 NS_IMETHODIMP nsPrintSettingsX::_Assign(nsIPrintSettings *aPS)
485 nsPrintSettingsX *printSettingsX = static_cast<nsPrintSettingsX*>(aPS);
487 return NS_ERROR_UNEXPECTED;
488 *this = *printSettingsX;
493 OSStatus nsPrintSettingsX::CreateDefaultPageFormat(PMPrintSession aSession, PMPageFormat& outFormat)
495 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
498 PMPageFormat pageFormat;
500 outFormat = kPMNoPageFormat;
501 status = ::PMCreatePageFormat(&pageFormat);
502 if (status == noErr && pageFormat != kPMNoPageFormat) {
503 status = ::PMSessionDefaultPageFormat(aSession, pageFormat);
504 if (status == noErr) {
505 outFormat = pageFormat;
511 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(noErr);
515 OSStatus nsPrintSettingsX::CreateDefaultPrintSettings(PMPrintSession aSession, PMPrintSettings& outSettings)
517 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
520 PMPrintSettings printSettings;
522 outSettings = kPMNoPrintSettings;
523 status = ::PMCreatePrintSettings(&printSettings);
524 if (status == noErr && printSettings != kPMNoPrintSettings) {
525 status = ::PMSessionDefaultPrintSettings(aSession, printSettings);
526 if (status == noErr) {
527 outSettings = printSettings;
533 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(noErr);