Back to index

lightning-sunbird  0.9+nobinonly
nsDeviceContextXlib.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *   Peter Hartshorn <peter@igelaus.com.au>
00025  *   Ken Faulkner <faulkner@igelaus.com.au>
00026  *   Tony Tsui <tony@igelaus.com.au>
00027  *   Tim Copperfield <timecop@network.email.ne.jp>
00028  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00029  *
00030  * Alternatively, the contents of this file may be used under the terms of
00031  * either of the GNU General Public License Version 2 or later (the "GPL"),
00032  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00033  * in which case the provisions of the GPL or the LGPL are applicable instead
00034  * of those above. If you wish to allow use of your version of this file only
00035  * under the terms of either the GPL or the LGPL, and not to allow others to
00036  * use your version of this file under the terms of the MPL, indicate your
00037  * decision by deleting the provisions above and replace them with the notice
00038  * and other provisions required by the GPL or the LGPL. If you do not delete
00039  * the provisions above, a recipient may use your version of this file under
00040  * the terms of any one of the MPL, the GPL or the LGPL.
00041  *
00042  * ***** END LICENSE BLOCK ***** */
00043 
00044 #include "nsRenderingContextXlib.h"
00045 #include "nsDrawingSurfaceXlib.h"
00046 #include "nsDeviceContextXlib.h"
00047 #include "nsIPref.h"
00048 #include "nsIServiceManager.h"
00049 #include "nsGfxCIID.h"
00050 #include "nspr.h"
00051 
00052 #include "nsFontMetricsXlib.h"
00053 
00054 #include "xlibrgb.h"
00055 #include <X11/Xatom.h>
00056 
00057 #include "nsDeviceContextSpecXlib.h"
00058 
00059 #ifdef USE_POSTSCRIPT
00060 #include "nsGfxPSCID.h"
00061 #include "nsIDeviceContextPS.h"
00062 #endif /* USE_POSTSCRIPT */
00063 #ifdef USE_XPRINT
00064 #include "nsGfxXPrintCID.h"
00065 #include "nsIDeviceContextXPrint.h"
00066 #endif /* USE_XPRINT */
00067 
00068 static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
00069 
00070 #define XLIB_DEFAULT_FONT1 "-*-helvetica-medium-r-*--*-120-*-*-*-*-iso8859-1"
00071 #define XLIB_DEFAULT_FONT2 "-*-fixed-medium-r-*-*-*-120-*-*-*-*-*-*"
00072 
00073 #ifdef PR_LOGGING 
00074 static PRLogModuleInfo *DeviceContextXlibLM = PR_NewLogModule("DeviceContextXlib");
00075 #endif /* PR_LOGGING */ 
00076 
00077 /* global default font handle */
00078 static XFontStruct *mDefaultFont = nsnull;
00079 
00080 nsDeviceContextXlib::nsDeviceContextXlib()
00081   : nsDeviceContextX()
00082 {
00083   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::nsDeviceContextXlib()\n"));
00084   mTwipsToPixels = 1.0;
00085   mPixelsToTwips = 1.0;
00086   mNumCells = 0;
00087   mSurface = nsnull;
00088   mDisplay = nsnull;
00089   mScreen = nsnull;
00090   mVisual = nsnull;
00091   mDepth = 0;
00092 
00093   mWidthFloat = 0.0f;
00094   mHeightFloat = 0.0f;
00095   mWidth = -1;
00096   mHeight = -1;
00097   mXlibRgbHandle = xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE);
00098   if (!mXlibRgbHandle)
00099     abort();
00100     
00101   mContextCounter++;
00102 }
00103 
00104 nsDeviceContextXlib::~nsDeviceContextXlib()
00105 {
00106   nsIDrawingSurfaceXlib *surf = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, mSurface);
00107   NS_IF_RELEASE(surf);
00108   mSurface = nsnull;
00109   
00110   mContextCounter--;
00111   
00112   if (mContextCounter == 0)
00113   {
00114     DeleteRenderingContextXlibContext(mRCContext);
00115     DeleteFontMetricsXlibContext(mFontMetricsContext);
00116     mRCContext          = nsnull;
00117     mFontMetricsContext = nsnull;
00118   }
00119 }
00120 
00121 nsFontMetricsXlibContext      *nsDeviceContextXlib::mFontMetricsContext = nsnull;
00122 nsRenderingContextXlibContext *nsDeviceContextXlib::mRCContext          = nsnull;
00123 int                            nsDeviceContextXlib::mContextCounter     = 0;
00124 
00125 NS_IMETHODIMP nsDeviceContextXlib::Init(nsNativeWidget aNativeWidget)
00126 {
00127   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::Init()\n"));
00128 
00129   mWidget = aNativeWidget;
00130 
00131   mDisplay = xxlib_rgb_get_display(mXlibRgbHandle);
00132   mScreen  = xxlib_rgb_get_screen(mXlibRgbHandle);
00133   mVisual  = xxlib_rgb_get_visual(mXlibRgbHandle);
00134   mDepth   = xxlib_rgb_get_depth(mXlibRgbHandle);
00135 
00136   if (!mDefaultFont)
00137     mDefaultFont = XLoadQueryFont(mDisplay, XLIB_DEFAULT_FONT1);
00138 
00139   if (!mDefaultFont)
00140     mDefaultFont = XLoadQueryFont(mDisplay, XLIB_DEFAULT_FONT2);
00141 
00142 #ifdef DEBUG
00143   static PRBool once = PR_TRUE;
00144 
00145   if (once)
00146   {
00147     once = PR_FALSE;
00148 
00149     printf("nsDeviceContextXlib::Init(dpy=%p  screen=%p  visual=%p  depth=%d)\n",
00150            mDisplay,
00151            mScreen,
00152            mVisual,
00153            mDepth);
00154   }
00155 #endif /* DEBUG */
00156 
00157   return CommonInit();
00158 }
00159 
00160 nsresult
00161 nsDeviceContextXlib::CommonInit(void)
00162 {
00163   nsresult rv = NS_OK;;
00164 
00165   // FIXME: PeterH
00166   // This was set to 100 dpi, then later on in the function is was changed
00167   // to a default of 96dpi IF we had a preference component. We need to 
00168   // find a way to get the actual server dpi for a comparison ala GTK.
00169   static nscoord dpi = 96;
00170   static int initialized = 0;
00171 
00172   if (!initialized) {
00173     initialized = 1;
00174     nsresult res;
00175     nsCOMPtr<nsIPref> prefs(do_GetService(kPrefCID, &res));
00176     if (NS_SUCCEEDED(res) && prefs) {
00177       PRInt32 intVal = 96;
00178       res = prefs->GetIntPref("layout.css.dpi", &intVal);
00179       if (NS_SUCCEEDED(res)) {
00180         if (intVal) {
00181           dpi = intVal;
00182         }
00183         else {
00184           // Compute dpi of display
00185           float screenWidth = float(XWidthOfScreen(mScreen));
00186           float screenWidthIn = float(XWidthMMOfScreen(mScreen)) / 25.4f;
00187           dpi = nscoord(screenWidth / screenWidthIn);
00188         }
00189       }
00190     }
00191   }
00192 
00193   // Do extra rounding (based on GTK). KenF
00194   mPixelsToTwips = float(NSToIntRound(float(NSIntPointsToTwips(72)) / float(dpi)));
00195   mTwipsToPixels = 1.0f / mPixelsToTwips;
00196 
00197   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("GFX: dpi=%d t2p=%g p2t=%g\n", dpi, mTwipsToPixels, mPixelsToTwips));
00198 
00199   mWidthFloat  = (float) XWidthOfScreen(mScreen);
00200   mHeightFloat = (float) XHeightOfScreen(mScreen);
00201 
00202   DeviceContextImpl::CommonInit();
00203   
00204   if (!mFontMetricsContext)
00205   {
00206     rv = CreateFontMetricsXlibContext(this, PR_FALSE, &mFontMetricsContext);
00207     if (NS_FAILED(rv))
00208       return rv;
00209   }
00210 
00211   if (!mRCContext)
00212   {
00213     rv = CreateRenderingContextXlibContext(this, &mRCContext);
00214     if (NS_FAILED(rv))
00215       return rv;
00216   }
00217    
00218   return rv;
00219 }
00220 
00221 NS_IMETHODIMP nsDeviceContextXlib::CreateRenderingContext(nsIRenderingContext *&aContext)
00222 {
00223   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::CreateRenderingContext()\n"));
00224 
00225 #ifdef NS_PRINT_PREVIEW
00226   /* Defer to Alt when there is one */
00227   if (mAltDC && ((mUseAltDC & kUseAltDCFor_CREATERC_PAINT) || (mUseAltDC & kUseAltDCFor_CREATERC_REFLOW))) {
00228     return mAltDC->CreateRenderingContext(aContext);
00229   }
00230 #endif /* NS_PRINT_PREVIEW */
00231 
00232   nsIRenderingContext      *context;
00233   nsDrawingSurfaceXlibImpl *surface = nsnull;
00234   nsresult                  rv;
00235 
00236   context = new nsRenderingContextXlib();
00237 
00238   if (nsnull != context) {
00239     NS_ADDREF(context);
00240     surface = new nsDrawingSurfaceXlibImpl();
00241     if (nsnull != surface) {
00242       xGC *gc = new xGC(mDisplay, (Drawable)mWidget, 0, nsnull);
00243       rv = surface->Init(mXlibRgbHandle,
00244                          (Drawable)mWidget, 
00245                          gc);
00246 
00247       if (NS_SUCCEEDED(rv)) {
00248         rv = context->Init(this, surface);
00249       }
00250     }
00251     else {
00252       rv = NS_ERROR_OUT_OF_MEMORY;
00253     }
00254   }
00255   else {
00256     rv = NS_ERROR_OUT_OF_MEMORY;
00257   }
00258   
00259   if (NS_FAILED(rv)) {
00260     NS_IF_RELEASE(context);
00261   }
00262   aContext = context;
00263   
00264   return rv;
00265 }
00266 
00267 NS_IMETHODIMP nsDeviceContextXlib::CreateRenderingContextInstance(nsIRenderingContext *&aContext)
00268 {
00269   nsCOMPtr<nsIRenderingContext> renderingContext = new nsRenderingContextXlib();
00270   if (!renderingContext)
00271     return NS_ERROR_OUT_OF_MEMORY;
00272          
00273   aContext = renderingContext;
00274   NS_ADDREF(aContext);
00275   
00276   return NS_OK;
00277 }
00278 
00279 NS_IMETHODIMP nsDeviceContextXlib::SupportsNativeWidgets(PRBool &aSupportsWidgets)
00280 {
00281   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::SupportsNativeWidgets()\n"));
00282   aSupportsWidgets = PR_TRUE;
00283   return NS_OK;
00284 }
00285 
00286 NS_IMETHODIMP nsDeviceContextXlib::GetScrollBarDimensions(float &aWidth, float &aHeight) const
00287 {
00288   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::GetScrollBarDimensions()\n"));
00289   float scale;
00290   GetCanonicalPixelScale(scale);
00291   // XXX Oh, yeah.  These are hard coded.
00292   aWidth = 15 * mPixelsToTwips * scale;
00293   aHeight = 15 * mPixelsToTwips * scale;
00294 
00295   return NS_OK;
00296 }
00297 
00298 NS_IMETHODIMP nsDeviceContextXlib::GetSystemFont(nsSystemFontID anID, nsFont *aFont) const
00299 {
00300   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::GetSystemFont()\n"));
00301 
00302   switch (anID) {
00303     case eSystemFont_Caption:              // css2
00304     case eSystemFont_Icon:
00305     case eSystemFont_Menu:
00306     case eSystemFont_MessageBox:
00307     case eSystemFont_SmallCaption:
00308     case eSystemFont_StatusBar:
00309     case eSystemFont_Window:                       // css3
00310     case eSystemFont_Document:
00311     case eSystemFont_Workspace:
00312     case eSystemFont_Desktop:
00313     case eSystemFont_Info:
00314     case eSystemFont_Dialog:
00315     case eSystemFont_Button:
00316     case eSystemFont_PullDownMenu:
00317     case eSystemFont_List:
00318     case eSystemFont_Field:
00319     case eSystemFont_Tooltips:             // moz
00320     case eSystemFont_Widget:
00321       aFont->style       = NS_FONT_STYLE_NORMAL;
00322       aFont->weight      = NS_FONT_WEIGHT_NORMAL;
00323       aFont->decorations = NS_FONT_DECORATION_NONE;
00324 
00325       if (!mDefaultFont)
00326         return NS_ERROR_FAILURE;
00327       else
00328       {
00329         char *fontName = nsnull;
00330         unsigned long pr = 0;
00331 
00332         ::XGetFontProperty(mDefaultFont, XA_FULL_NAME, &pr);
00333         if(pr)
00334           {
00335             fontName = XGetAtomName(mDisplay, pr);
00336             aFont->name.AssignWithConversion(fontName);
00337             ::XFree(fontName);
00338           }
00339   
00340         pr = 0;
00341         ::XGetFontProperty(mDefaultFont, XA_WEIGHT, &pr);
00342         if ( pr > 10 )
00343           aFont->weight = NS_FONT_WEIGHT_BOLD;
00344     
00345         pr = 0;
00346         Atom pixelSizeAtom = ::XInternAtom(mDisplay, "PIXEL_SIZE", 0);
00347         ::XGetFontProperty(mDefaultFont, pixelSizeAtom, &pr);
00348         if( pr )
00349           aFont->size = NSIntPixelsToTwips(pr, mPixelsToTwips);
00350 
00351         pr = 0;
00352         ::XGetFontProperty(mDefaultFont, XA_ITALIC_ANGLE, &pr );
00353         if( pr )
00354           aFont->style = NS_FONT_STYLE_ITALIC;
00355     
00356         pr = 0;
00357         ::XGetFontProperty(mDefaultFont, XA_UNDERLINE_THICKNESS, &pr);
00358         if( pr )
00359           aFont->decorations = NS_FONT_DECORATION_UNDERLINE;
00360       }
00361       break;
00362   }
00363 
00364   aFont->systemFont = PR_TRUE;
00365 
00366   return NS_OK;
00367 }
00368 
00369 NS_IMETHODIMP nsDeviceContextXlib::CheckFontExistence(const nsString& aFontName)
00370 {
00371   return nsFontMetricsXlib::FamilyExists(mFontMetricsContext, aFontName);
00372 }
00373 
00374 NS_IMETHODIMP nsDeviceContextXlib::GetDeviceSurfaceDimensions(PRInt32 &aWidth, PRInt32 &aHeight)
00375 {
00376 #ifdef NS_PRINT_PREVIEW                                                         
00377   /* Defer to Alt when there is one */
00378   if (mAltDC && (mUseAltDC & kUseAltDCFor_SURFACE_DIM)) {
00379     return mAltDC->GetDeviceSurfaceDimensions(aWidth, aHeight);
00380   }
00381 #endif /* NS_PRINT_PREVIEW */
00382  
00383   if (mWidth == -1)
00384     mWidth = NSToIntRound(mWidthFloat * mDevUnitsToAppUnits);
00385 
00386   if (mHeight == -1)
00387     mHeight = NSToIntRound(mHeightFloat * mDevUnitsToAppUnits);
00388 
00389   aWidth = mWidth;
00390   aHeight = mHeight;
00391 
00392   return NS_OK;
00393 }
00394 
00395 NS_IMETHODIMP nsDeviceContextXlib::GetRect(nsRect &aRect)
00396 {
00397   PRInt32 width, height;
00398   nsresult rv;
00399   rv = GetDeviceSurfaceDimensions(width, height);
00400   aRect.x = 0;
00401   aRect.y = 0;
00402   aRect.width = width;
00403   aRect.height = height;
00404   return rv;
00405 }
00406 
00407 NS_IMETHODIMP nsDeviceContextXlib::GetClientRect(nsRect &aRect)
00408 {
00409   PRInt32 width, height;
00410   nsresult rv;
00411   rv = GetDeviceSurfaceDimensions(width, height);
00412   aRect.x = 0;
00413   aRect.y = 0;
00414   aRect.width = width;
00415   aRect.height = height;
00416   return rv;
00417 }
00418 
00419 NS_IMETHODIMP nsDeviceContextXlib::GetDeviceContextFor(nsIDeviceContextSpec *aDevice,
00420                                                        nsIDeviceContext *&aContext)
00421 {
00422   nsresult                 rv;
00423   PrintMethod              method;
00424   nsDeviceContextSpecXlib *spec = NS_STATIC_CAST(nsDeviceContextSpecXlib *, aDevice);
00425   
00426   rv = spec->GetPrintMethod(method);
00427   if (NS_FAILED(rv)) 
00428     return rv;
00429 
00430 #ifdef USE_XPRINT
00431   if (method == pmXprint) { // XPRINT
00432     static NS_DEFINE_CID(kCDeviceContextXp, NS_DEVICECONTEXTXP_CID);
00433     nsCOMPtr<nsIDeviceContextXp> dcxp(do_CreateInstance(kCDeviceContextXp, &rv));
00434     NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create Xp Device context.");    
00435     if (NS_FAILED(rv)) 
00436       return NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE;
00437     
00438     rv = dcxp->SetSpec(aDevice);
00439     if (NS_FAILED(rv)) 
00440       return rv;
00441     
00442     rv = dcxp->InitDeviceContextXP((nsIDeviceContext*)aContext,
00443                                    (nsIDeviceContext*)this);
00444     if (NS_FAILED(rv)) 
00445       return rv;
00446       
00447     rv = dcxp->QueryInterface(NS_GET_IID(nsIDeviceContext),
00448                               (void **)&aContext);
00449     return rv;
00450   }
00451   else
00452 #endif /* USE_XPRINT */
00453 #ifdef USE_POSTSCRIPT
00454   if (method == pmPostScript) { // PostScript
00455     // default/PS
00456     static NS_DEFINE_CID(kCDeviceContextPS, NS_DEVICECONTEXTPS_CID);
00457   
00458     // Create a Postscript device context 
00459     nsCOMPtr<nsIDeviceContextPS> dcps(do_CreateInstance(kCDeviceContextPS, &rv));
00460     NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create PS Device context.");
00461     if (NS_FAILED(rv)) 
00462       return NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE;
00463   
00464     rv = dcps->SetSpec(aDevice);
00465     if (NS_FAILED(rv)) 
00466       return rv;
00467       
00468     rv = dcps->InitDeviceContextPS((nsIDeviceContext*)aContext,
00469                                    (nsIDeviceContext*)this);
00470     if (NS_FAILED(rv)) 
00471       return rv;
00472 
00473     rv = dcps->QueryInterface(NS_GET_IID(nsIDeviceContext),
00474                               (void **)&aContext);
00475     return rv;
00476   }
00477 #endif /* USE_POSTSCRIPT */  
00478   
00479   NS_WARNING("no print module created.");
00480   return NS_ERROR_UNEXPECTED;
00481 }
00482 
00483 NS_IMETHODIMP nsDeviceContextXlib::BeginDocument(PRUnichar * aTitle, PRUnichar* aPrintToFileName, PRInt32 aStartPage, PRInt32 aEndPage)
00484 {
00485   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::BeginDocument()\n"));
00486   return NS_OK;
00487 }
00488 
00489 NS_IMETHODIMP nsDeviceContextXlib::EndDocument(void)
00490 {
00491   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::EndDocument()\n"));
00492   return NS_OK;
00493 }
00494 
00495 NS_IMETHODIMP nsDeviceContextXlib::AbortDocument(void)
00496 {
00497   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::EndDocument()\n"));
00498   return NS_OK;
00499 }
00500 
00501 NS_IMETHODIMP nsDeviceContextXlib::BeginPage(void)
00502 {
00503   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::BeginPage()\n"));
00504   return NS_OK;
00505 }
00506 
00507 NS_IMETHODIMP nsDeviceContextXlib::EndPage(void)
00508 {
00509   PR_LOG(DeviceContextXlibLM, PR_LOG_DEBUG, ("nsDeviceContextXlib::EndPage()\n"));
00510   return NS_OK;
00511 }
00512 
00513 class nsFontCacheXlib : public nsFontCache
00514 {
00515 public:
00516   /* override DeviceContextImpl::CreateFontCache() */
00517   virtual nsresult CreateFontMetricsInstance(nsIFontMetrics** aResult);
00518 };
00519 
00520 
00521 nsresult nsFontCacheXlib::CreateFontMetricsInstance(nsIFontMetrics** aResult)
00522 {
00523   NS_PRECONDITION(aResult, "null out param");
00524   nsIFontMetrics *fm = new nsFontMetricsXlib();
00525   if (!fm)
00526     return NS_ERROR_OUT_OF_MEMORY;
00527   NS_ADDREF(fm);
00528   *aResult = fm;
00529   return NS_OK;
00530 }
00531 
00532 /* override DeviceContextImpl::CreateFontCache() */
00533 NS_IMETHODIMP nsDeviceContextXlib::CreateFontCache()
00534 {
00535   mFontCache = new nsFontCacheXlib();
00536   if (nsnull == mFontCache) {
00537     return NS_ERROR_OUT_OF_MEMORY;
00538   }
00539   return mFontCache->Init(this);
00540 }
00541 
00542