Back to index

lightning-sunbird  0.9+nobinonly
nsDeviceContextPS.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ex: set tabstop=8 softtabstop=2 shiftwidth=2 expandtab: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00025  *   Ken Herron <kherron@fastmail.us>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "gfx-config.h"
00042  
00043 /* PostScript/Xprint print modules do not support more than one object
00044  * instance because they use global vars which cannot be shared between
00045  * multiple instances...
00046  * bug 119491 ("Cleanup global vars in PostScript and Xprint modules) will fix
00047  * that...
00048  */
00049 #define WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS 1
00050 
00051 #define FORCE_PR_LOG /* Allow logging in the release build */
00052 #define PR_LOGGING 1
00053 #include "prlog.h"
00054 
00055 #include "nsDeviceContextPS.h"
00056 #include "nsRenderingContextPS.h"
00057 #include "nsIServiceManager.h"
00058 #include "nsIPref.h"
00059 #include "nsString.h"
00060 #include "nsFontMetricsPS.h"
00061 #include "nsPostScriptObj.h"
00062 #include "nspr.h"
00063 #include "nsILanguageAtomService.h"
00064 #include "nsPrintJobPS.h"
00065 #include "nsPrintJobFactoryPS.h"
00066 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
00067 #include "nsType1.h"
00068 #endif
00069 
00070 #ifdef PR_LOGGING
00071 static PRLogModuleInfo *nsDeviceContextPSLM = PR_NewLogModule("nsDeviceContextPS");
00072 #endif /* PR_LOGGING */
00073 
00074 nsIAtom* gUsersLocale = nsnull;
00075 
00076 #ifdef WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS
00077 static int instance_counter = 0;
00078 #endif /* WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS */
00079 
00080 static PRBool
00081 FreePSFontGeneratorList(nsHashKey *aKey, void *aData, void *aClosure)
00082 {
00083   nsPSFontGenerator *psFG = (nsPSFontGenerator*)aData;
00084   if (psFG) {
00085     delete psFG;
00086     psFG = nsnull;
00087   }
00088   return PR_TRUE;
00089 }
00090 
00095 nsDeviceContextPS :: nsDeviceContextPS()
00096   : DeviceContextImpl(),
00097   mSpec(nsnull),
00098   mParentDeviceContext(nsnull),
00099   mPrintJob(nsnull),
00100   mPSObj(nsnull),
00101   mPSFontGeneratorList(nsnull)
00102 { 
00103   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::nsDeviceContextPS()\n"));
00104 
00105 #ifdef WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS
00106   instance_counter++;
00107   NS_ASSERTION(instance_counter < 2, "Cannot have more than one print device context.");
00108 #endif /* WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS */
00109 }
00110 
00115 nsDeviceContextPS::~nsDeviceContextPS()
00116 {
00117   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::~nsDeviceContextPS()\n"));
00118 
00119   delete mPSObj;
00120   delete mPrintJob;
00121   mParentDeviceContext = nsnull;
00122 
00123 #ifdef WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS
00124   instance_counter--;
00125   NS_ASSERTION(instance_counter >= 0, "We cannot have less than zero instances.");
00126 #endif /* WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS */
00127 
00128   if (mPSFontGeneratorList) {
00129     mPSFontGeneratorList->Reset(FreePSFontGeneratorList, nsnull);
00130     delete mPSFontGeneratorList;
00131     mPSFontGeneratorList = nsnull;
00132   }
00133   NS_IF_RELEASE(gUsersLocale);
00134 }
00135 
00136 NS_IMETHODIMP
00137 nsDeviceContextPS::SetSpec(nsIDeviceContextSpec* aSpec)
00138 {
00139   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::SetSpec()\n"));
00140   NS_PRECONDITION(!mPSObj, "Already have a postscript object");
00141   NS_PRECONDITION(!mPrintJob, "Already have a printjob object");
00142 
00143 #ifdef WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS
00144   NS_ASSERTION(instance_counter < 2, "Cannot have more than one print device context.");
00145   if (instance_counter > 1) {
00146     return NS_ERROR_GFX_PRINTER_PRINT_WHILE_PREVIEW;
00147   }
00148 #endif /* WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS */
00149 
00150   mSpec = aSpec;
00151 
00152   mPSObj = new nsPostScriptObj();
00153   if (!mPSObj)
00154     return  NS_ERROR_OUT_OF_MEMORY; 
00155 
00156   nsresult rv;
00157   nsCOMPtr<nsIDeviceContextSpecPS> psSpec = do_QueryInterface(mSpec, &rv);
00158   if (NS_SUCCEEDED(rv)) {
00159     rv = mPSObj->Init(psSpec);
00160     if (NS_SUCCEEDED(rv))
00161       rv = nsPrintJobFactoryPS::CreatePrintJob(psSpec, mPrintJob);
00162   }
00163   if (NS_FAILED(rv)) {
00164     delete mPSObj;
00165     mPSObj = nsnull;
00166   }
00167   else {
00168     // Successfully allocated both PS and print job objects.
00169     // Determine which one will handle number-of-copies.
00170     int num_copies;
00171     psSpec->GetCopies(num_copies);
00172     if (NS_FAILED(mPrintJob->SetNumCopies(num_copies)))
00173       mPSObj->SetNumCopies(num_copies);
00174   }
00175 
00176   return rv;
00177 }
00178 
00179 NS_IMPL_ISUPPORTS_INHERITED1(nsDeviceContextPS,
00180                              DeviceContextImpl,
00181                              nsIDeviceContextPS)
00182 
00183 
00187 NS_IMETHODIMP
00188 nsDeviceContextPS::InitDeviceContextPS(nsIDeviceContext *aCreatingDeviceContext,nsIDeviceContext *aParentContext)
00189 {
00190   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::InitDeviceContextPS()\n"));
00191 
00192   float origscale, newscale;
00193   float t2d, a2d;
00194 
00195 #ifdef WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS
00196   NS_ASSERTION(instance_counter < 2, "Cannot have more than one print device context.");
00197   if (instance_counter > 1) {
00198     return NS_ERROR_GFX_PRINTER_PRINT_WHILE_PREVIEW;
00199   }
00200 #endif /* WE_DO_NOT_SUPPORT_MULTIPLE_PRINT_DEVICECONTEXTS */
00201 
00202   NS_ENSURE_ARG_POINTER(aParentContext);
00203 
00204   mDepth = 24; /* Our PostScript module code expects images and other stuff in 24bit RGB-format (8bits per gun)*/
00205 
00206   mTwipsToPixels = (float)72.0/(float)NSIntPointsToTwips(72);
00207   mPixelsToTwips = 1.0f / mTwipsToPixels;
00208 
00209   newscale = TwipsToDevUnits();
00210   origscale = aParentContext->TwipsToDevUnits();
00211   mCPixelScale = newscale / origscale;
00212 
00213   t2d = aParentContext->TwipsToDevUnits();
00214   a2d = aParentContext->AppUnitsToDevUnits();
00215 
00216   mAppUnitsToDevUnits = (a2d / t2d) * mTwipsToPixels;
00217   mDevUnitsToAppUnits = 1.0f / mAppUnitsToDevUnits;
00218 
00219   mParentDeviceContext = aParentContext;
00220 
00221   mPSFontGeneratorList = new nsHashtable();
00222   NS_ENSURE_TRUE(mPSFontGeneratorList, NS_ERROR_OUT_OF_MEMORY);
00223  
00224   nsresult rv;
00225   nsCOMPtr<nsIPref> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
00226 #ifdef MOZ_ENABLE_XFT
00227   if (NS_SUCCEEDED(rv)) {
00228       rv = pref->GetBoolPref("font.FreeType2.printing", &mFTPEnable);
00229       if (NS_FAILED(rv))
00230         mFTPEnable = PR_FALSE;
00231   }
00232 #else 
00233   mFTPEnable = PR_FALSE;
00234 #ifdef MOZ_ENABLE_FREETYPE2
00235   if (NS_SUCCEEDED(rv)) {
00236     rv = pref->GetBoolPref("font.FreeType2.enable", &mFTPEnable);
00237     if (NS_FAILED(rv))
00238       mFTPEnable = PR_FALSE;
00239     if (mFTPEnable) {
00240       rv = pref->GetBoolPref("font.FreeType2.printing", &mFTPEnable);
00241       if (NS_FAILED(rv))
00242         mFTPEnable = PR_FALSE;
00243     }
00244   }
00245 #endif
00246 #endif
00247   
00248   // the user's locale
00249   nsCOMPtr<nsILanguageAtomService> langService;
00250   langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
00251   if (langService) {
00252     NS_IF_ADDREF(gUsersLocale = langService->GetLocaleLanguageGroup());
00253   }
00254   if (!gUsersLocale) {
00255     gUsersLocale = NS_NewAtom("x-western");
00256   }
00257 
00258   return NS_OK;
00259 }
00260 
00268 NS_IMETHODIMP nsDeviceContextPS::CreateRenderingContext(nsIRenderingContext *&aContext)
00269 {
00270   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::CreateRenderingContext()\n"));
00271 
00272   nsresult rv;
00273    
00274   aContext = nsnull;
00275 
00276   NS_ENSURE_TRUE(mPSObj != nsnull, NS_ERROR_NULL_POINTER);
00277 
00278   nsCOMPtr<nsRenderingContextPS> renderingContext = new nsRenderingContextPS();
00279   if (!renderingContext)
00280     return NS_ERROR_OUT_OF_MEMORY;
00281      
00282   rv = renderingContext->Init(this);
00283 
00284   if (NS_SUCCEEDED(rv)) {
00285     aContext = renderingContext;
00286     NS_ADDREF(aContext);
00287   }
00288 
00289   return rv;
00290 }
00291 
00292 NS_IMETHODIMP nsDeviceContextPS::CreateRenderingContextInstance(nsIRenderingContext *&aContext)
00293 {
00294   nsCOMPtr<nsIRenderingContext> renderingContext = new nsRenderingContextPS();
00295   if (!renderingContext)
00296     return NS_ERROR_OUT_OF_MEMORY;
00297          
00298   aContext = renderingContext;
00299   NS_ADDREF(aContext);
00300   
00301   return NS_OK;
00302 }
00303 
00308 NS_IMETHODIMP nsDeviceContextPS::SupportsNativeWidgets(PRBool &aSupportsWidgets)
00309 {
00310   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::SupportsNativeWidgets()\n"));
00311 
00312   aSupportsWidgets = PR_FALSE;
00313   return NS_OK;
00314 }
00315 
00320 NS_IMETHODIMP nsDeviceContextPS::GetScrollBarDimensions(float &aWidth, float &aHeight) const
00321 {
00322   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::GetScrollBarDimensions()\n"));
00323 
00324   //XXX: Hardcoded values for Postscript
00325   float scale;
00326   GetCanonicalPixelScale(scale);
00327   aWidth  = 20.f * scale;
00328   aHeight = 20.f * scale;
00329   return NS_OK;
00330 }
00331 
00336 NS_IMETHODIMP nsDeviceContextPS::GetDepth(PRUint32& aDepth)
00337 {
00338   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::GetDepth(mDepth=%d)\n", mDepth));
00339 
00340   return mDepth;
00341 }
00342 
00347 NS_IMETHODIMP nsDeviceContextPS::CheckFontExistence(const nsString& aFontName)
00348 {
00349   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::CheckFontExistence()\n"));
00350 
00351   // XXX this needs to find out if this font is supported for postscript
00352   return NS_OK;
00353 }
00354 
00355 NS_IMETHODIMP nsDeviceContextPS::GetSystemFont(nsSystemFontID aID, nsFont *aFont) const
00356 {
00357   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::GetSystemFont()\n"));
00358 
00359   if (mParentDeviceContext != nsnull) {
00360     return mParentDeviceContext->GetSystemFont(aID, aFont);
00361   }
00362   return NS_ERROR_FAILURE;
00363 }
00364 
00369 NS_IMETHODIMP nsDeviceContextPS::GetDeviceSurfaceDimensions(PRInt32 &aWidth, PRInt32 &aHeight)
00370 {
00371   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::GetDeviceSurfaceDimensions()\n"));
00372 
00373   NS_ENSURE_TRUE(mPSObj && mPSObj->mPrintSetup, NS_ERROR_NULL_POINTER);
00374 
00375   // Height and width are already in twips
00376   aWidth  = mPSObj->mPrintSetup->width;
00377   aHeight = mPSObj->mPrintSetup->height;
00378 
00379   return NS_OK;
00380 }
00381 
00385 NS_IMETHODIMP nsDeviceContextPS::GetRect(nsRect &aRect)
00386 {
00387   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::GetRect()\n"));
00388 
00389   NS_ENSURE_TRUE(mPSObj != nsnull, NS_ERROR_NULL_POINTER);
00390 
00391   PRInt32 width, height;
00392   nsresult rv;
00393   rv = GetDeviceSurfaceDimensions(width, height);
00394   aRect.x = 0;
00395   aRect.y = 0;
00396   aRect.width = width;
00397   aRect.height = height;
00398   return rv;
00399 }
00400 
00404 NS_IMETHODIMP nsDeviceContextPS::GetClientRect(nsRect &aRect)
00405 {
00406   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::GetClientRect()\n"));
00407 
00408   return GetRect(aRect);
00409 }
00410 
00415 NS_IMETHODIMP nsDeviceContextPS::GetDeviceContextFor(nsIDeviceContextSpec *aDevice, nsIDeviceContext *&aContext)
00416 {
00417   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::GetDeviceContextFor()\n"));
00418   aContext = nsnull;
00419   return NS_OK;
00420 }
00421 
00426 NS_IMETHODIMP nsDeviceContextPS::BeginDocument(PRUnichar * aTitle, PRUnichar* aPrintToFileName, PRInt32 aStartPage, PRInt32 aEndPage)
00427 {
00428   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::BeginDocument()\n"));
00429 
00430   NS_ENSURE_TRUE(mPSObj != nsnull, NS_ERROR_NULL_POINTER);
00431   NS_ENSURE_TRUE(mPrintJob != nsnull, NS_ERROR_NULL_POINTER);
00432 
00433   mPSObj->settitle(aTitle); 
00434   mPrintJob->SetJobTitle(aTitle);
00435   return NS_OK;
00436 }
00437 
00438 static PRBool PR_CALLBACK
00439 GeneratePSFontCallback(nsHashKey *aKey, void *aData, void* aClosure)
00440 {
00441   nsPSFontGenerator* psFontGenerator = (nsPSFontGenerator*)aData;
00442   NS_ENSURE_TRUE(psFontGenerator && aClosure, PR_FALSE);
00443 
00444   if (aClosure)
00445     psFontGenerator->GeneratePSFont((FILE *)aClosure);
00446   return PR_TRUE;
00447 }
00448 
00453 NS_IMETHODIMP nsDeviceContextPS::EndDocument(void)
00454 {
00455   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::EndDocument()\n"));
00456 
00457   NS_ENSURE_TRUE(mPSObj != nsnull, NS_ERROR_NULL_POINTER);
00458 
00459   // Finish the document and print it...
00460   nsresult rv = mPSObj->end_document();
00461   if (NS_SUCCEEDED(rv)) {
00462     FILE *submitFP;
00463     rv = mPrintJob->StartSubmission(&submitFP);
00464     if (NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED == rv) {
00465       // This was probably a print-preview operation
00466       rv = NS_OK;
00467     }
00468     else if (NS_SUCCEEDED(rv)) {
00469       NS_ASSERTION(submitFP, "No print job submission handle");
00470 
00471       // Start writing the print job to the job handler
00472 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
00473       mPSObj->write_prolog(submitFP, mFTPEnable);
00474 #else 
00475       mPSObj->write_prolog(submitFP);
00476 #endif
00477 
00478       /* Core of TrueType printing:
00479        *   enumerate items("nsPSFontGenerator") in hashtable
00480        *   to generate Type1 fonts and output to Postscript file
00481        */
00482       if (mPSFontGeneratorList)
00483         mPSFontGeneratorList->Enumerate(GeneratePSFontCallback,
00484             (void *) submitFP);
00485 
00486       rv = mPSObj->write_script(submitFP);
00487       if (NS_SUCCEEDED(rv))
00488         rv = mPrintJob->FinishSubmission();
00489     }
00490   }
00491 
00492   delete mPrintJob;
00493   mPrintJob = nsnull;
00494 
00495   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG,
00496       ("nsDeviceContextPS::EndDocument() return value %d\n", rv));
00497 
00498   return rv;
00499 }
00500 
00501 
00505 NS_IMETHODIMP nsDeviceContextPS::AbortDocument(void)
00506 {
00507   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::AbortDocument()\n"));
00508 
00509   NS_ENSURE_TRUE(mPSObj != nsnull, NS_ERROR_NULL_POINTER);
00510   
00511   delete mPrintJob;
00512   mPrintJob = nsnull;
00513   return NS_OK;
00514 }
00515 
00520 NS_IMETHODIMP nsDeviceContextPS::BeginPage(void)
00521 {
00522   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::BeginPage()\n"));
00523 
00524   NS_ENSURE_TRUE(mPSObj != nsnull, NS_ERROR_NULL_POINTER);
00525 
00526   // begin the page
00527   mPSObj->begin_page(); 
00528   return NS_OK;
00529 }
00530 
00535 NS_IMETHODIMP nsDeviceContextPS::EndPage(void)
00536 {
00537   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::EndPage()\n"));
00538 
00539   NS_ENSURE_TRUE(mPSObj != nsnull, NS_ERROR_NULL_POINTER);
00540 
00541   // end the page
00542   mPSObj->end_page();
00543   return NS_OK;
00544 }
00545 
00546 class nsFontCachePS : public nsFontCache
00547 {
00548 public:
00549   /* override DeviceContextImpl::CreateFontCache() */
00550   virtual nsresult CreateFontMetricsInstance(nsIFontMetrics** aResult);
00551 };
00552 
00553 
00554 nsresult nsFontCachePS::CreateFontMetricsInstance(nsIFontMetrics** aResult)
00555 {
00556   NS_PRECONDITION(aResult, "null out param");
00557   nsIFontMetrics *fm = new nsFontMetricsPS();
00558   if (!fm)
00559     return NS_ERROR_OUT_OF_MEMORY;
00560   NS_ADDREF(fm);
00561   *aResult = fm;
00562   return NS_OK;
00563 }
00564 
00565 /* override DeviceContextImpl::CreateFontCache() */
00566 NS_IMETHODIMP nsDeviceContextPS::CreateFontCache()
00567 {
00568   PR_LOG(nsDeviceContextPSLM, PR_LOG_DEBUG, ("nsDeviceContextPS::CreateFontCache()\n"));
00569 
00570   mFontCache = new nsFontCachePS();
00571   if (!mFontCache) {
00572     return NS_ERROR_OUT_OF_MEMORY;
00573   }
00574   
00575   return mFontCache->Init(this);
00576 }
00577 
00578