Back to index

lightning-sunbird  0.9+nobinonly
nsDeviceContextGTK.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 // vim:cindent:ts=2:et:sw=2:
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  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include <math.h>
00041 
00042 #include "nspr.h"
00043 #include "nsIPref.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsCRT.h"
00046 
00047 #include "nsDeviceContextGTK.h"
00048 #include "nsGfxCIID.h"
00049 
00050 #ifdef USE_POSTSCRIPT
00051 #include "nsGfxPSCID.h"
00052 #include "nsIDeviceContextPS.h"
00053 #endif /* USE_POSTSCRIPT */
00054 #ifdef USE_XPRINT
00055 #include "nsGfxXPrintCID.h"
00056 #include "nsIDeviceContextXPrint.h"
00057 #endif /* USE_XPRINT */
00058 
00059 #include "nsFontMetricsUtils.h"
00060 
00061 #include <gdk/gdk.h>
00062 #include <gdk/gdkx.h>
00063 
00064 #ifdef MOZ_WIDGET_GTK
00065 #include "gdksuperwin.h"
00066 #endif /* MOZ_WIDGET_GTK */
00067 
00068 #ifdef MOZ_WIDGET_GTK2
00069 #include <pango/pango.h>
00070 #include <pango/pangox.h>
00071 #include <pango/pango-fontmap.h>
00072 #endif
00073 
00074 #ifdef MOZ_ENABLE_XFT
00075 #include "nsFontMetricsUtils.h"
00076 #include <X11/Xlib.h>
00077 #include <X11/Xft/Xft.h>
00078 
00079 static PRInt32 GetXftDPI(void);
00080 #endif
00081 
00082 #include <X11/Xatom.h>
00083 
00084 #include "nsDeviceContextSpecG.h"
00085 
00086 static PRInt32 GetOSDPI(void);
00087 
00088 static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
00089 
00090 #define GDK_DEFAULT_FONT1 "-*-helvetica-medium-r-*--*-120-*-*-*-*-iso8859-1"
00091 #define GDK_DEFAULT_FONT2 "-*-fixed-medium-r-*-*-*-120-*-*-*-*-*-*"
00092 
00093 #ifdef MOZ_WIDGET_GTK
00094 // this is specific to gtk 1.2
00095 extern NS_IMPORT_(GdkFont *) default_font;
00096 #endif /* MOZ_WIDGET_GTK */
00097 
00102 class nsSystemFontsGTK {
00103 
00104   public:
00105     nsSystemFontsGTK(float aPixelsToTwips);
00106 
00107     const nsFont& GetDefaultFont() { return mDefaultFont; }
00108     const nsFont& GetMenuFont() { return mMenuFont; }
00109     const nsFont& GetFieldFont() { return mFieldFont; }
00110     const nsFont& GetButtonFont() { return mButtonFont; }
00111 
00112   private:
00113     nsresult GetSystemFontInfo(GtkWidget *aWidget, nsFont* aFont,
00114                                float aPixelsToTwips) const;
00115 
00116     /*
00117      * The following system font constants exist:
00118      *
00119      * css2: http://www.w3.org/TR/REC-CSS2/fonts.html#x27
00120      * eSystemFont_Caption, eSystemFont_Icon, eSystemFont_Menu,
00121      * eSystemFont_MessageBox, eSystemFont_SmallCaption,
00122      * eSystemFont_StatusBar,
00123      * // css3
00124      * eSystemFont_Window, eSystemFont_Document,
00125      * eSystemFont_Workspace, eSystemFont_Desktop,
00126      * eSystemFont_Info, eSystemFont_Dialog,
00127      * eSystemFont_Button, eSystemFont_PullDownMenu,
00128      * eSystemFont_List, eSystemFont_Field,
00129      * // moz
00130      * eSystemFont_Tooltips, eSystemFont_Widget
00131      */
00132     nsFont mDefaultFont;
00133     nsFont mButtonFont;
00134     nsFont mFieldFont;
00135     nsFont mMenuFont;
00136 };
00137 
00138 
00139 nscoord nsDeviceContextGTK::mDpi = 96;
00140 static nsSystemFontsGTK *gSystemFonts = nsnull;
00141 
00142 nsDeviceContextGTK::nsDeviceContextGTK()
00143   : DeviceContextImpl()
00144 {
00145   mTwipsToPixels = 1.0;
00146   mPixelsToTwips = 1.0;
00147   mDepth = 0 ;
00148   mNumCells = 0;
00149 
00150   mWidthFloat = 0.0f;
00151   mHeightFloat = 0.0f;
00152   mWidth = -1;
00153   mHeight = -1;
00154   mDeviceWindow = nsnull;
00155 }
00156 
00157 nsDeviceContextGTK::~nsDeviceContextGTK()
00158 {
00159   nsresult rv;
00160   nsCOMPtr<nsIPref> prefs = do_GetService(kPrefCID, &rv);
00161   if (NS_SUCCEEDED(rv)) {
00162     prefs->UnregisterCallback("layout.css.dpi",
00163                               prefChanged, (void *)this);
00164   }
00165 }
00166 
00167 /* static */ void nsDeviceContextGTK::Shutdown()
00168 {
00169   if (gSystemFonts) {
00170     delete gSystemFonts;
00171     gSystemFonts = nsnull;
00172   }
00173 }
00174 
00175 NS_IMETHODIMP nsDeviceContextGTK::Init(nsNativeWidget aNativeWidget)
00176 {
00177   GtkRequisition req;
00178   GtkWidget *sb;
00179   
00180   // get the screen object and its width/height
00181   // XXXRight now this will only get the primary monitor.
00182 
00183   if (!mScreenManager)
00184     mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
00185   if (!mScreenManager) {
00186     return NS_ERROR_FAILURE;
00187   }
00188 
00189 #ifdef MOZ_WIDGET_GTK
00190 
00191   if (aNativeWidget) {
00192     // superwin?
00193     if (GDK_IS_SUPERWIN(aNativeWidget)) {
00194       mDeviceWindow = GDK_SUPERWIN(aNativeWidget)->shell_window;
00195     }
00196     // gtk widget?
00197     else if (GTK_IS_WIDGET(aNativeWidget)) {
00198       mDeviceWindow = GTK_WIDGET(aNativeWidget)->window;
00199     }
00200     // must be a bin_window
00201     else {
00202       mDeviceWindow = NS_STATIC_CAST(GdkWindow *, aNativeWidget);
00203     }
00204   }
00205 
00206 #endif /* MOZ_WIDGET_GTK */
00207 
00208 #ifdef MOZ_WIDGET_GTK2
00209 
00210   if (aNativeWidget) {
00211     // can only be a gdk window
00212     if (GDK_IS_WINDOW(aNativeWidget))
00213       mDeviceWindow = GDK_WINDOW(aNativeWidget);
00214     else 
00215       NS_WARNING("unsupported native widget type!");
00216   }
00217 
00218 #endif
00219 
00220   nsCOMPtr<nsIScreen> screen;
00221   mScreenManager->GetPrimaryScreen ( getter_AddRefs(screen) );
00222   if ( screen ) {
00223     PRInt32 x, y, width, height, depth;
00224     screen->GetRect ( &x, &y, &width, &height );
00225     screen->GetPixelDepth ( &depth );
00226     mWidthFloat = float(width);
00227     mHeightFloat = float(height);
00228     mDepth = NS_STATIC_CAST ( PRUint32, depth );
00229   }
00230     
00231   static int initialized = 0;
00232   PRInt32 prefVal = -1;
00233   if (!initialized) {
00234     initialized = 1;
00235 
00236     // Set prefVal the value of the preference
00237     // "layout.css.dpi"
00238     // or -1 if we can't get it.
00239     // If it's negative, we pretend it's not set.
00240     // If it's 0, it means force use of the operating system's logical
00241     // resolution.
00242     // If it's positive, we use it as the logical resolution
00243     nsresult res;
00244 
00245     nsCOMPtr<nsIPref> prefs(do_GetService(kPrefCID, &res));
00246     if (NS_SUCCEEDED(res) && prefs) {
00247       res = prefs->GetIntPref("layout.css.dpi", &prefVal);
00248       if (NS_FAILED(res)) {
00249         prefVal = -1;
00250       }
00251       prefs->RegisterCallback("layout.css.dpi", prefChanged,
00252                               (void *)this);
00253     }
00254 
00255     SetDPI(prefVal);
00256   } else {
00257     SetDPI(mDpi); // to setup p2t and t2p
00258   }
00259 
00260   sb = gtk_vscrollbar_new(NULL);
00261   gtk_widget_ref(sb);
00262   gtk_object_sink(GTK_OBJECT(sb));
00263 #ifdef MOZ_WIDGET_GTK2
00264   gtk_widget_ensure_style(sb);
00265   gtk_widget_queue_resize(sb);
00266 #endif /* MOZ_WIDGET_GTK2 */
00267   gtk_widget_size_request(sb,&req);
00268   mScrollbarWidth = req.width;
00269   gtk_widget_destroy(sb);
00270   gtk_widget_unref(sb);
00271   
00272   sb = gtk_hscrollbar_new(NULL);
00273   gtk_widget_ref(sb);
00274   gtk_object_sink(GTK_OBJECT(sb));
00275 #ifdef MOZ_WIDGET_GTK2
00276   gtk_widget_ensure_style(sb);
00277   gtk_widget_queue_resize(sb);
00278 #endif /* MOZ_WIDGET_GTK2 */
00279   gtk_widget_size_request(sb,&req);
00280   mScrollbarHeight = req.height;
00281   gtk_widget_destroy(sb);
00282   gtk_widget_unref(sb);
00283 
00284 #ifdef DEBUG
00285   static PRBool once = PR_TRUE;
00286   if (once) {
00287     printf("GFX: dpi=%d t2p=%g p2t=%g depth=%d\n", mDpi, mTwipsToPixels, mPixelsToTwips,mDepth);
00288     once = PR_FALSE;
00289   }
00290 #endif
00291 
00292   DeviceContextImpl::CommonInit();
00293 
00294   return NS_OK;
00295 }
00296 
00297 NS_IMETHODIMP nsDeviceContextGTK::CreateRenderingContext(nsIRenderingContext *&aContext)
00298 {
00299 #ifdef NS_PRINT_PREVIEW
00300   // Defer to Alt when there is one
00301   if (mAltDC && ((mUseAltDC & kUseAltDCFor_CREATERC_PAINT) || (mUseAltDC & kUseAltDCFor_CREATERC_REFLOW))) {
00302     return mAltDC->CreateRenderingContext(aContext);
00303   }
00304 #endif
00305 
00306   nsIRenderingContext *pContext;
00307   nsresult             rv;
00308   nsDrawingSurfaceGTK  *surf;
00309   GtkWidget *w;
00310 
00311   w = (GtkWidget*)mWidget;
00312 
00313   // to call init for this, we need to have a valid nsDrawingSurfaceGTK created
00314   pContext = new nsRenderingContextGTK();
00315 
00316   if (nsnull != pContext)
00317   {
00318     NS_ADDREF(pContext);
00319 
00320     // create the nsDrawingSurfaceGTK
00321     surf = new nsDrawingSurfaceGTK();
00322 
00323     if (surf && w)
00324       {
00325         GdkDrawable *gwin = nsnull;
00326         GdkDrawable *win = nsnull;
00327         // FIXME
00328         if (GTK_IS_LAYOUT(w))
00329           gwin = (GdkDrawable*)GTK_LAYOUT(w)->bin_window;
00330         else
00331           gwin = (GdkDrawable*)(w)->window;
00332 
00333         // window might not be realized... ugh
00334         if (gwin)
00335           gdk_window_ref(gwin);
00336         else {
00337           win = gdk_pixmap_new(nsnull,
00338                                w->allocation.width,
00339                                w->allocation.height,
00340                                gdk_rgb_get_visual()->depth);
00341 #ifdef MOZ_WIDGET_GTK2
00342           gdk_drawable_set_colormap(win, gdk_rgb_get_colormap());
00343 #endif
00344         }
00345 
00346         GdkGC *gc = gdk_gc_new(win);
00347 
00348         // init the nsDrawingSurfaceGTK
00349         rv = surf->Init(win,gc);
00350 
00351         if (NS_OK == rv)
00352           // Init the nsRenderingContextGTK
00353           rv = pContext->Init(this, surf);
00354       }
00355     else
00356       rv = NS_ERROR_OUT_OF_MEMORY;
00357   }
00358   else
00359     rv = NS_ERROR_OUT_OF_MEMORY;
00360 
00361   if (NS_OK != rv)
00362   {
00363     NS_IF_RELEASE(pContext);
00364   }
00365 
00366   aContext = pContext;
00367 
00368   return rv;
00369 }
00370 
00371 NS_IMETHODIMP nsDeviceContextGTK::CreateRenderingContextInstance(nsIRenderingContext *&aContext)
00372 {
00373   nsCOMPtr<nsIRenderingContext> renderingContext = new nsRenderingContextGTK();
00374   if (!renderingContext)
00375     return NS_ERROR_OUT_OF_MEMORY;
00376          
00377   aContext = renderingContext;
00378   NS_ADDREF(aContext);
00379   
00380   return NS_OK;
00381 }
00382 
00383 NS_IMETHODIMP nsDeviceContextGTK::SupportsNativeWidgets(PRBool &aSupportsWidgets)
00384 {
00385   //XXX it is very critical that this not lie!! MMP
00386   // read the comments in the mac code for this
00387   aSupportsWidgets = PR_TRUE;
00388 
00389   return NS_OK;
00390 }
00391 
00392 NS_IMETHODIMP nsDeviceContextGTK::GetScrollBarDimensions(float &aWidth, float &aHeight) const
00393 {
00394   float scale;
00395   GetCanonicalPixelScale(scale);
00396   aWidth = mScrollbarWidth * mPixelsToTwips * scale;
00397   aHeight = mScrollbarHeight * mPixelsToTwips * scale;
00398 
00399   return NS_OK;
00400 }
00401 
00402 NS_IMETHODIMP nsDeviceContextGTK::GetSystemFont(nsSystemFontID aID, nsFont *aFont) const
00403 {
00404   nsresult status = NS_OK;
00405 
00406   if (!gSystemFonts) {
00407     gSystemFonts = new nsSystemFontsGTK(mPixelsToTwips);
00408   }
00409 
00410   switch (aID) {
00411     case eSystemFont_Menu:         // css2
00412     case eSystemFont_PullDownMenu: // css3
00413         *aFont = gSystemFonts->GetMenuFont();
00414         break;
00415 
00416     case eSystemFont_Field:        // css3
00417     case eSystemFont_List:         // css3
00418         *aFont = gSystemFonts->GetFieldFont();
00419         break;
00420 
00421     case eSystemFont_Button:       // css3
00422         *aFont = gSystemFonts->GetButtonFont();
00423         break;
00424 
00425     case eSystemFont_Caption:      // css2
00426     case eSystemFont_Icon:         // css2
00427     case eSystemFont_MessageBox:   // css2
00428     case eSystemFont_SmallCaption: // css2
00429     case eSystemFont_StatusBar:    // css2
00430     case eSystemFont_Window:       // css3
00431     case eSystemFont_Document:     // css3
00432     case eSystemFont_Workspace:    // css3
00433     case eSystemFont_Desktop:      // css3
00434     case eSystemFont_Info:         // css3
00435     case eSystemFont_Dialog:       // css3
00436     case eSystemFont_Tooltips:     // moz
00437     case eSystemFont_Widget:       // moz
00438         *aFont = gSystemFonts->GetDefaultFont();
00439         break;
00440   }
00441 
00442   return status;
00443 }
00444 
00445 NS_IMETHODIMP nsDeviceContextGTK::CheckFontExistence(const nsString& aFontName)
00446 {
00447   return NS_FontMetricsFamilyExists(this, aFontName);
00448 }
00449 
00450 NS_IMETHODIMP nsDeviceContextGTK::GetDeviceSurfaceDimensions(PRInt32 &aWidth, PRInt32 &aHeight)
00451 {
00452 #ifdef NS_PRINT_PREVIEW
00453   // Defer to Alt when there is one
00454   if (mAltDC && (mUseAltDC & kUseAltDCFor_SURFACE_DIM)) {
00455     return mAltDC->GetDeviceSurfaceDimensions(aWidth, aHeight);
00456   }
00457 #endif
00458 
00459   if (mWidth == -1)
00460     mWidth = NSToIntRound(mWidthFloat * mDevUnitsToAppUnits);
00461 
00462   if (mHeight == -1)
00463     mHeight = NSToIntRound(mHeightFloat * mDevUnitsToAppUnits);
00464 
00465   aWidth = mWidth;
00466   aHeight = mHeight;
00467 
00468   return NS_OK;
00469 }
00470 
00471 
00472 
00473 NS_IMETHODIMP nsDeviceContextGTK::GetRect(nsRect &aRect)
00474 {
00475   // if we have an initialized widget for this device context, use it
00476   // to try and get real screen coordinates.
00477   if (mDeviceWindow) {
00478     gint x, y, width, height, depth;
00479     x = y = width = height = 0;
00480 
00481     gdk_window_get_geometry(mDeviceWindow, &x, &y, &width, &height,
00482                             &depth);
00483     gdk_window_get_origin(mDeviceWindow, &x, &y);
00484 
00485     nsCOMPtr<nsIScreen> screen;
00486     mScreenManager->ScreenForRect(x, y, width, height, getter_AddRefs(screen));
00487     screen->GetRect(&aRect.x, &aRect.y, &aRect.width, &aRect.height);
00488     aRect.x = NSToIntRound(mDevUnitsToAppUnits * aRect.x);
00489     aRect.y = NSToIntRound(mDevUnitsToAppUnits * aRect.y);
00490     aRect.width = NSToIntRound(mDevUnitsToAppUnits * aRect.width);
00491     aRect.height = NSToIntRound(mDevUnitsToAppUnits * aRect.height);
00492   }
00493   else {
00494     PRInt32 width, height;
00495     GetDeviceSurfaceDimensions(width, height);
00496     aRect.x = 0;
00497     aRect.y = 0;
00498     aRect.width = width;
00499     aRect.height = height;
00500   }
00501   return NS_OK;
00502 }
00503 
00504 
00505 NS_IMETHODIMP nsDeviceContextGTK::GetClientRect(nsRect &aRect)
00506 {
00507   // if we have an initialized widget for this device context, use it
00508   // to try and get real screen coordinates.
00509   if (mDeviceWindow) {
00510     gint x, y, width, height, depth;
00511     x = y = width = height = 0;
00512 
00513     gdk_window_get_geometry(mDeviceWindow, &x, &y, &width, &height,
00514                             &depth);
00515     gdk_window_get_origin(mDeviceWindow, &x, &y);
00516 
00517     nsCOMPtr<nsIScreen> screen;
00518     mScreenManager->ScreenForRect(x, y, width, height, getter_AddRefs(screen));
00519     screen->GetAvailRect(&aRect.x, &aRect.y, &aRect.width, &aRect.height);
00520     aRect.x = NSToIntRound(mDevUnitsToAppUnits * aRect.x);
00521     aRect.y = NSToIntRound(mDevUnitsToAppUnits * aRect.y);
00522     aRect.width = NSToIntRound(mDevUnitsToAppUnits * aRect.width);
00523     aRect.height = NSToIntRound(mDevUnitsToAppUnits * aRect.height);
00524   }
00525   else {
00526     PRInt32 width, height;
00527     GetDeviceSurfaceDimensions(width, height);
00528     aRect.x = 0;
00529     aRect.y = 0;
00530     aRect.width = width;
00531     aRect.height = height;
00532   }
00533 
00534   return NS_OK;
00535 }
00536 
00537 NS_IMETHODIMP nsDeviceContextGTK::GetDeviceContextFor(nsIDeviceContextSpec *aDevice,
00538                                                        nsIDeviceContext *&aContext)
00539 {
00540   nsresult                 rv;
00541   PrintMethod              method;
00542   nsDeviceContextSpecGTK  *spec = NS_STATIC_CAST(nsDeviceContextSpecGTK *, aDevice);
00543   
00544   rv = spec->GetPrintMethod(method);
00545   if (NS_FAILED(rv)) 
00546     return rv;
00547 
00548 #ifdef USE_XPRINT
00549   if (method == pmXprint) { // XPRINT
00550     static NS_DEFINE_CID(kCDeviceContextXp, NS_DEVICECONTEXTXP_CID);
00551     nsCOMPtr<nsIDeviceContextXp> dcxp(do_CreateInstance(kCDeviceContextXp, &rv));
00552     NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create Xp Device context.");    
00553     if (NS_FAILED(rv)) 
00554       return NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE;
00555     
00556     rv = dcxp->SetSpec(aDevice);
00557     if (NS_FAILED(rv)) 
00558       return rv;
00559     
00560     rv = dcxp->InitDeviceContextXP((nsIDeviceContext*)aContext,
00561                                    (nsIDeviceContext*)this);
00562     if (NS_FAILED(rv)) 
00563       return rv;
00564       
00565     rv = dcxp->QueryInterface(NS_GET_IID(nsIDeviceContext),
00566                               (void **)&aContext);
00567     return rv;
00568   }
00569   else
00570 #endif /* USE_XPRINT */
00571 #ifdef USE_POSTSCRIPT
00572   if (method == pmPostScript) { // PostScript
00573     // default/PS
00574     static NS_DEFINE_CID(kCDeviceContextPS, NS_DEVICECONTEXTPS_CID);
00575   
00576     // Create a Postscript device context 
00577     nsCOMPtr<nsIDeviceContextPS> dcps(do_CreateInstance(kCDeviceContextPS, &rv));
00578     NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create PS Device context.");
00579     if (NS_FAILED(rv)) 
00580       return NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE;
00581   
00582     rv = dcps->SetSpec(aDevice);
00583     if (NS_FAILED(rv)) 
00584       return rv;
00585       
00586     rv = dcps->InitDeviceContextPS((nsIDeviceContext*)aContext,
00587                                    (nsIDeviceContext*)this);
00588     if (NS_FAILED(rv)) 
00589       return rv;
00590 
00591     rv = dcps->QueryInterface(NS_GET_IID(nsIDeviceContext),
00592                               (void **)&aContext);
00593     return rv;
00594   }
00595 #endif /* USE_POSTSCRIPT */
00596   
00597   NS_WARNING("no print module created.");
00598   return NS_ERROR_UNEXPECTED;
00599 }
00600 
00601 NS_IMETHODIMP nsDeviceContextGTK::BeginDocument(PRUnichar * aTitle, PRUnichar* aPrintToFileName, PRInt32 aStartPage, PRInt32 aEndPage)
00602 {
00603   return NS_OK;
00604 }
00605 
00606 NS_IMETHODIMP nsDeviceContextGTK::EndDocument(void)
00607 {
00608   return NS_OK;
00609 }
00610 
00611 NS_IMETHODIMP nsDeviceContextGTK::AbortDocument(void)
00612 {
00613   return NS_OK;
00614 }
00615 
00616 NS_IMETHODIMP nsDeviceContextGTK::BeginPage(void)
00617 {
00618   return NS_OK;
00619 }
00620 
00621 NS_IMETHODIMP nsDeviceContextGTK::EndPage(void)
00622 {
00623   return NS_OK;
00624 }
00625 
00626 NS_IMETHODIMP nsDeviceContextGTK::GetDepth(PRUint32& aDepth)
00627 {
00628   aDepth = mDepth;
00629   return NS_OK;
00630 }
00631 
00632 nsresult
00633 nsDeviceContextGTK::SetDPI(PRInt32 aPrefDPI)
00634 {
00635   PRInt32 OSVal = GetOSDPI();
00636 
00637   if (aPrefDPI > 0) {
00638     // If there's a valid pref value for the logical resolution,
00639     // use it.
00640     mDpi = aPrefDPI;
00641   } else if ((aPrefDPI == 0) || (OSVal > 96)) {
00642     // Either if the pref is 0 (force use of OS value) or the OS
00643     // value is bigger than 96, use the OS value.
00644     mDpi = OSVal;
00645   } else {
00646     // if we couldn't get the pref or it's negative, and the OS
00647     // value is under 96ppi, then use 96.
00648     mDpi = 96;
00649   }
00650   
00651   int pt2t = 72;
00652 
00653   // make p2t a nice round number - this prevents rounding problems
00654   mPixelsToTwips = float(NSToIntRound(float(NSIntPointsToTwips(pt2t)) / float(mDpi)));
00655   mTwipsToPixels = 1.0f / mPixelsToTwips;
00656 
00657   // XXX need to reflow all documents
00658   return NS_OK;
00659 }
00660 
00661 int nsDeviceContextGTK::prefChanged(const char *aPref, void *aClosure)
00662 {
00663   nsDeviceContextGTK *context = (nsDeviceContextGTK*)aClosure;
00664   nsresult rv;
00665   
00666   if (nsCRT::strcmp(aPref, "layout.css.dpi")==0) {
00667     PRInt32 dpi;
00668     nsCOMPtr<nsIPref> prefs(do_GetService(kPrefCID, &rv));
00669     rv = prefs->GetIntPref(aPref, &dpi);
00670     if (NS_SUCCEEDED(rv))
00671       context->SetDPI(dpi);
00672 
00673     // If this pref changes, we have to clear our cache of stored system
00674     // fonts.
00675     ClearCachedSystemFonts();
00676   }
00677 
00678   return 0;
00679 }
00680 
00681 void nsDeviceContextGTK::ClearCachedSystemFonts()
00682 {
00683   //clear our cache of stored system fonts
00684   if (gSystemFonts) {
00685     delete gSystemFonts;
00686     gSystemFonts = nsnull;
00687   }
00688 }
00689 
00690 #define DEFAULT_TWIP_FONT_SIZE 240
00691 
00692 nsSystemFontsGTK::nsSystemFontsGTK(float aPixelsToTwips)
00693   : mDefaultFont("sans-serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
00694                  NS_FONT_WEIGHT_NORMAL, NS_FONT_DECORATION_NONE,
00695                  DEFAULT_TWIP_FONT_SIZE),
00696     mButtonFont("sans-serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
00697                 NS_FONT_WEIGHT_NORMAL, NS_FONT_DECORATION_NONE,
00698                 DEFAULT_TWIP_FONT_SIZE),
00699     mFieldFont("sans-serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
00700                NS_FONT_WEIGHT_NORMAL, NS_FONT_DECORATION_NONE,
00701                DEFAULT_TWIP_FONT_SIZE),
00702     mMenuFont("sans-serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
00703                NS_FONT_WEIGHT_NORMAL, NS_FONT_DECORATION_NONE,
00704                DEFAULT_TWIP_FONT_SIZE)
00705 {
00706   /*
00707    * Much of the widget creation code here is similar to the code in
00708    * nsLookAndFeel::InitColors().
00709    */
00710 
00711   // mDefaultFont
00712   GtkWidget *label = gtk_label_new("M");
00713   GtkWidget *parent = gtk_fixed_new();
00714   GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
00715 
00716   gtk_container_add(GTK_CONTAINER(parent), label);
00717   gtk_container_add(GTK_CONTAINER(window), parent);
00718 
00719   gtk_widget_ensure_style(label);
00720 
00721   GetSystemFontInfo(label, &mDefaultFont, aPixelsToTwips);
00722 
00723   gtk_widget_destroy(window);  // no unref, windows are different
00724 
00725   // mFieldFont
00726   GtkWidget *entry = gtk_entry_new();
00727   parent = gtk_fixed_new();
00728   window = gtk_window_new(GTK_WINDOW_POPUP);
00729 
00730   gtk_container_add(GTK_CONTAINER(parent), entry);
00731   gtk_container_add(GTK_CONTAINER(window), parent);
00732   gtk_widget_ensure_style(entry);
00733 
00734   GetSystemFontInfo(entry, &mFieldFont, aPixelsToTwips);
00735 
00736   gtk_widget_destroy(window);  // no unref, windows are different
00737 
00738   // mMenuFont
00739   GtkWidget *accel_label = gtk_accel_label_new("M");
00740   GtkWidget *menuitem = gtk_menu_item_new();
00741   GtkWidget *menu = gtk_menu_new();
00742   gtk_object_ref(GTK_OBJECT(menu));
00743   gtk_object_sink(GTK_OBJECT(menu));
00744 
00745   gtk_container_add(GTK_CONTAINER(menuitem), accel_label);
00746   gtk_menu_append(GTK_MENU(menu), menuitem);
00747 
00748   gtk_widget_ensure_style(accel_label);
00749 
00750   GetSystemFontInfo(accel_label, &mMenuFont, aPixelsToTwips);
00751 
00752   gtk_widget_unref(menu);
00753 
00754   // mButtonFont
00755   parent = gtk_fixed_new();
00756   GtkWidget *button = gtk_button_new();
00757   label = gtk_label_new("M");
00758   window = gtk_window_new(GTK_WINDOW_POPUP);
00759           
00760   gtk_container_add(GTK_CONTAINER(button), label);
00761   gtk_container_add(GTK_CONTAINER(parent), button);
00762   gtk_container_add(GTK_CONTAINER(window), parent);
00763 
00764   gtk_widget_ensure_style(label);
00765 
00766   GetSystemFontInfo(label, &mButtonFont, aPixelsToTwips);
00767 
00768   gtk_widget_destroy(window);  // no unref, windows are different
00769 
00770 }
00771 
00772 #if 0 // debugging code to list the font properties
00773 static void
00774 ListFontProps(XFontStruct *aFont, Display *aDisplay)
00775 {
00776   printf("\n\n");
00777   for (int i = 0, n = aFont->n_properties; i < n; ++i) {
00778     XFontProp *prop = aFont->properties + i;
00779     char *atomName = ::XGetAtomName(aDisplay, prop->name);
00780     // 500 is just a guess
00781     char *cardName = (prop->card32 > 0 && prop->card32 < 500)
00782                        ? ::XGetAtomName(aDisplay, prop->card32)
00783                        : 0;
00784     printf("%s : %ld (%s)\n", atomName, prop->card32, cardName?cardName:"");
00785     ::XFree(atomName);
00786     if (cardName)
00787       ::XFree(cardName);
00788   }
00789   printf("\n\n");
00790 }
00791 #endif
00792 
00793 #if defined(MOZ_ENABLE_COREXFONTS) || defined(MOZ_WIDGET_GTK)
00794 
00795 #define LOCATE_MINUS(pos, str)  { \
00796    pos = str.FindChar('-'); \
00797    if (pos < 0) \
00798      return ; \
00799   }
00800 #define NEXT_MINUS(pos, str) { \
00801    pos = str.FindChar('-', pos+1); \
00802    if (pos < 0) \
00803      return ; \
00804   }  
00805 
00806 static void
00807 AppendFontFFREName(nsString& aString, const char* aXLFDName)
00808 {
00809   // convert fontname from XFLD to FFRE and append, ie. from
00810   // -adobe-courier-medium-o-normal--14-140-75-75-m-90-iso8859-15
00811   // to
00812   // adobe-courier-iso8859-15
00813   nsCAutoString nameStr(aXLFDName);
00814   PRInt32 pos1, pos2;
00815   // remove first '-' and everything before it. 
00816   LOCATE_MINUS(pos1, nameStr);
00817   nameStr.Cut(0, pos1+1);
00818 
00819   // skip foundry and family name
00820   LOCATE_MINUS(pos1, nameStr);
00821   NEXT_MINUS(pos1, nameStr);
00822   pos2 = pos1;
00823 
00824   // find '-' just before charset registry
00825   for (PRInt32 i=0; i < 10; i++) {
00826     NEXT_MINUS(pos2, nameStr);
00827   }
00828 
00829   // remove everything in between
00830   nameStr.Cut(pos1, pos2-pos1);
00831 
00832   aString.AppendWithConversion(nameStr.get());
00833 }
00834 #endif /* MOZ_ENABLE_COREXFONTS || MOZ_WIDGET_GTK*/
00835 
00836 #ifdef MOZ_WIDGET_GTK
00837 static void
00838 AppendFontName(XFontStruct* aFontStruct, nsString& aString, Display *aDisplay)
00839 {
00840   unsigned long pr = 0;
00841   // we first append the FFRE name to reconstruct font more faithfully
00842   unsigned long font_atom = gdk_atom_intern("FONT", FALSE);
00843   if (::XGetFontProperty(aFontStruct, font_atom, &pr) && pr) {
00844     char* xlfdName = ::XGetAtomName(aDisplay, pr);
00845     AppendFontFFREName(aString, xlfdName);
00846     ::XFree(xlfdName);
00847   }
00848  
00849   aString.Append(PRUnichar(','));
00850 
00851   // next, we need to append family name to cover more encodings.
00852   if ((::XGetFontProperty(aFontStruct, XA_FAMILY_NAME, &pr) ||
00853        ::XGetFontProperty(aFontStruct, XA_FULL_NAME, &pr)) &&
00854       pr) {
00855     char *fontName = ::XGetAtomName(aDisplay, pr);
00856     aString.AppendWithConversion(fontName);
00857     ::XFree(fontName);
00858   }
00859 }
00860 
00861 static PRUint16
00862 GetFontWeight(XFontStruct* aFontStruct, Display *aDisplay)
00863 {
00864   PRUint16 weight = NS_FONT_WEIGHT_NORMAL;
00865 
00866   // WEIGHT_NAME seems more reliable than WEIGHT, where 10 can mean
00867   // anything.  Check both, and make it bold if either says so.
00868   unsigned long pr = 0;
00869   Atom weightName = ::XInternAtom(aDisplay, "WEIGHT_NAME", True);
00870   if (weightName != None) {
00871     if (::XGetFontProperty(aFontStruct, weightName, &pr) && pr) {
00872       char *weightString = ::XGetAtomName(aDisplay, pr);
00873       if (nsCRT::strcasecmp(weightString, "bold") == 0)
00874         weight = NS_FONT_WEIGHT_BOLD;
00875       ::XFree(weightString);
00876     }
00877   }
00878 
00879   pr = 0;
00880   if (::XGetFontProperty(aFontStruct, XA_WEIGHT, &pr) && pr > 10 )
00881     weight = NS_FONT_WEIGHT_BOLD;
00882 
00883   return weight;
00884 }
00885 
00886 static nscoord
00887 GetFontSize(XFontStruct *aFontStruct, float aPixelsToTwips)
00888 {
00889   unsigned long pr = 0;
00890   Atom pixelSizeAtom = ::XInternAtom(GDK_DISPLAY(), "PIXEL_SIZE", 0);
00891   if (!::XGetFontProperty(aFontStruct, pixelSizeAtom, &pr) || !pr)
00892     return DEFAULT_TWIP_FONT_SIZE;
00893   return NSIntPixelsToTwips(pr, aPixelsToTwips);
00894 }
00895 
00896 nsresult
00897 nsSystemFontsGTK::GetSystemFontInfo(GtkWidget *aWidget, nsFont* aFont,
00898                                     float aPixelsToTwips) const
00899 {
00900   GtkStyle *style = gtk_widget_get_style(aWidget);
00901 
00902   GdkFont *theFont = style->font;
00903 
00904   aFont->style       = NS_FONT_STYLE_NORMAL;
00905   aFont->weight      = NS_FONT_WEIGHT_NORMAL;
00906   aFont->decorations = NS_FONT_DECORATION_NONE;
00907   
00908   // do we have the default_font defined by GTK/GDK then
00909   // we use it, if not then we load helvetica, if not then
00910   // we load fixed font else we error out.
00911   if (!theFont)
00912     theFont = default_font; // GTK default font
00913 
00914   if (!theFont)
00915     theFont = ::gdk_font_load( GDK_DEFAULT_FONT1 );
00916   
00917   if (!theFont)
00918     theFont = ::gdk_font_load( GDK_DEFAULT_FONT2 );
00919   
00920   if (!theFont)
00921     return NS_ERROR_FAILURE;
00922 
00923   Display *fontDisplay = GDK_FONT_XDISPLAY(theFont);
00924   if (theFont->type == GDK_FONT_FONT) {
00925     XFontStruct *fontStruct =
00926         NS_STATIC_CAST(XFontStruct*, GDK_FONT_XFONT(theFont));
00927 
00928     aFont->name.Truncate();
00929     AppendFontName(fontStruct, aFont->name, fontDisplay);
00930     aFont->weight = GetFontWeight(fontStruct, fontDisplay);
00931     aFont->size = GetFontSize(fontStruct, aPixelsToTwips);
00932   } else {
00933     NS_ASSERTION(theFont->type == GDK_FONT_FONTSET,
00934                  "theFont->type can only have two values");
00935 
00936     XFontSet fontSet = NS_REINTERPRET_CAST(XFontSet, GDK_FONT_XFONT(theFont));
00937     XFontStruct **fontStructs;
00938     char **fontNames;
00939     int numFonts = ::XFontsOfFontSet(fontSet, &fontStructs, &fontNames);
00940     if (numFonts == 0)
00941       return NS_ERROR_FAILURE;
00942 
00943     // Use the weight and size from the first font, but append all
00944     // the names.
00945     aFont->weight = GetFontWeight(*fontStructs, fontDisplay);
00946     aFont->size = GetFontSize(*fontStructs, aPixelsToTwips);
00947     nsString& fontName = aFont->name;
00948     fontName.Truncate();
00949     for (;;) {
00950       // we need to append FFRE name instead of family name in this case
00951       AppendFontFFREName(fontName, *fontNames);
00952       ++fontNames;
00953       --numFonts;
00954       if (numFonts == 0)
00955         break;
00956       fontName.Append(PRUnichar(','));
00957     }
00958   }
00959   return NS_OK;
00960 }
00961 #endif /* MOZ_WIDGET_GTK */
00962 
00963 #ifdef MOZ_WIDGET_GTK2
00964 
00965 #ifdef MOZ_ENABLE_COREXFONTS
00966 static void xlfd_from_pango_font_description(GtkWidget *aWidget,
00967                                              const PangoFontDescription *aFontDesc,
00968                                              nsString& aFontName);
00969 #endif /* MOZ_ENABLE_COREXFONTS */
00970 
00971 nsresult
00972 nsSystemFontsGTK::GetSystemFontInfo(GtkWidget *aWidget, nsFont* aFont,
00973                                     float aPixelsToTwips) const
00974 {
00975   GtkSettings *settings = gtk_widget_get_settings(aWidget);
00976 
00977   aFont->style       = NS_FONT_STYLE_NORMAL;
00978   aFont->decorations = NS_FONT_DECORATION_NONE;
00979 
00980   gchar *fontname;
00981   g_object_get(settings, "gtk-font-name", &fontname, NULL);
00982 
00983   PangoFontDescription *desc;
00984   desc = pango_font_description_from_string(fontname);
00985 
00986   aFont->systemFont = PR_TRUE;
00987 
00988   g_free(fontname);
00989 
00990   aFont->name.Truncate();
00991 #ifdef MOZ_ENABLE_XFT
00992   if (NS_IsXftEnabled()) {
00993     aFont->name.Assign(PRUnichar('"'));
00994     aFont->name.AppendWithConversion(pango_font_description_get_family(desc));
00995     aFont->name.Append(PRUnichar('"'));
00996   }
00997 #endif /* MOZ_ENABLE_XFT */
00998 
00999 #ifdef MOZ_ENABLE_COREXFONTS
01000   // if name already set by Xft, do nothing
01001   if (!aFont->name.Length()) {
01002     xlfd_from_pango_font_description(aWidget, desc, aFont->name);
01003   }
01004 #endif /* MOZ_ENABLE_COREXFONTS */
01005   aFont->weight = pango_font_description_get_weight(desc);
01006 
01007   float size = float(pango_font_description_get_size(desc) / PANGO_SCALE);
01008 #ifdef MOZ_ENABLE_XFT
01009   if (NS_IsXftEnabled()) {
01010     PRInt32 dpi = GetXftDPI();
01011     if (dpi != 0) {
01012       // pixels/inch * twips/pixel * inches/twip == 1, except it isn't, since
01013       // our idea of dpi may be different from Xft's.
01014       size *= float(dpi) * aPixelsToTwips * (1.0f/1440.0f);
01015     }
01016   }
01017 #endif /* MOZ_ENABLE_XFT */
01018   aFont->size = NSFloatPointsToTwips(size);
01019   
01020   pango_font_description_free(desc);
01021 
01022   return NS_OK;
01023 }
01024 #endif /* MOZ_WIDGET_GTK2 */
01025 
01026 #ifdef MOZ_WIDGET_GTK
01027 /* static */
01028 PRInt32
01029 GetOSDPI(void)
01030 {
01031 
01032 #ifdef MOZ_ENABLE_XFT
01033   // try to get it from xft
01034   if (NS_IsXftEnabled()) {
01035     PRInt32 xftdpi = GetXftDPI();
01036     if (xftdpi)
01037       return xftdpi;
01038   }
01039 #endif /* MOZ_ENABLE_XFT */
01040 
01041   // Set OSVal to what the operating system thinks the logical resolution is.
01042   float screenWidthIn = float(::gdk_screen_width_mm()) / 25.4f;
01043   return NSToCoordRound(float(::gdk_screen_width()) / screenWidthIn);
01044 }
01045 #endif /* MOZ_WIDGET_GTK */
01046 
01047 #ifdef MOZ_WIDGET_GTK2
01048 /* static */
01049 PRInt32
01050 GetOSDPI(void)
01051 {
01052   GtkSettings *settings = gtk_settings_get_default();
01053 
01054   // first try to get the gtk2 dpi
01055   gint dpi = 0;
01056 
01057   // See if there's a gtk-xft-dpi object on the settings object - note
01058   // that we don't have to free the spec since it isn't addrefed
01059   // before being returned.  It's just part of an internal object.
01060   // The gtk-xft-dpi setting is included in rh8 and might be included
01061   // in later versions of gtk, so we conditionally check for it.
01062   GParamSpec *spec;
01063   spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(settings)),
01064                                       "gtk-xft-dpi");
01065   if (spec) {
01066     g_object_get(G_OBJECT(settings),
01067                  "gtk-xft-dpi", &dpi,
01068                  NULL);
01069   }
01070 
01071   if (dpi > 0)
01072     return NSToCoordRound(dpi / 1024.0);
01073 
01074 #ifdef MOZ_ENABLE_XFT
01075   // try to get it from xft
01076   PRInt32 xftdpi = GetXftDPI();
01077 
01078   if (xftdpi)
01079     return xftdpi;
01080 #endif /* MOZ_ENABLE_XFT */
01081   
01082   // fall back to the physical resolution
01083   float screenWidthIn = float(::gdk_screen_width_mm()) / 25.4f;
01084   return NSToCoordRound(float(::gdk_screen_width()) / screenWidthIn);
01085 }
01086 #endif /* MOZ_WIDGET_GTK2 */
01087 
01088 #ifdef MOZ_ENABLE_XFT
01089 /* static */
01090 PRInt32
01091 GetXftDPI(void)
01092 {
01093   char *val = XGetDefault(GDK_DISPLAY(), "Xft", "dpi");
01094   if (val) {
01095     char *e;
01096     double d = strtod(val, &e);
01097 
01098     if (e != val)
01099       return NSToCoordRound(d);
01100   }
01101 
01102   return 0;
01103 }
01104 #endif /* MOZ_ENABLE_XFT */
01105 
01106 #if defined(MOZ_WIDGET_GTK2) && defined(MOZ_ENABLE_COREXFONTS)
01107 // xlfd_from_pango_font_description copied from vte, which was
01108 // written by nalin@redhat.com, and added some codes.
01109 static void
01110 xlfd_from_pango_font_description(GtkWidget *aWidget,
01111          const PangoFontDescription *aFontDesc,
01112                                  nsString& aFontName)
01113 {
01114   char *spec;
01115   PangoContext *context;
01116   PangoFont *font;
01117   PangoXSubfont *subfont_ids;
01118   PangoFontMap *fontmap;
01119   int *subfont_charsets, i, count = 0;
01120   char *tmp, *subfont;
01121   char *encodings[] = {
01122     "ascii-0",
01123     "big5-0",
01124     "dos-437",
01125     "dos-737",
01126     "gb18030.2000-0",
01127     "gb18030.2000-1",
01128     "gb2312.1980-0",
01129     "iso8859-1",
01130     "iso8859-2",
01131     "iso8859-3",
01132     "iso8859-4",
01133     "iso8859-5",
01134     "iso8859-7",
01135     "iso8859-8",
01136     "iso8859-9",
01137     "iso8859-10",
01138     "iso8859-15",
01139     "iso10646-0",
01140     "iso10646-1",
01141     "jisx0201.1976-0",
01142     "jisx0208.1983-0",
01143     "jisx0208.1990-0",
01144     "jisx0208.1997-0",
01145     "jisx0212.1990-0",
01146     "jisx0213.2000-1",
01147     "jisx0213.2000-2",
01148     "koi8-r",
01149     "koi8-u",
01150     "koi8-ub",
01151     "ksc5601.1987-0",
01152     "ksc5601.1992-3",
01153     "tis620-0",
01154     "iso8859-13",
01155     "microsoft-cp1251"
01156     "misc-fontspecific",
01157   };
01158 #if XlibSpecificationRelease >= 6
01159   XOM xom;
01160 #endif
01161   if (!aFontDesc) {
01162     return;
01163   }
01164 
01165   context = gtk_widget_get_pango_context(GTK_WIDGET(aWidget));
01166 
01167   pango_context_set_language (context, gtk_get_default_language ());
01168   fontmap = pango_x_font_map_for_display(GDK_DISPLAY());
01169 
01170   if (!fontmap) {
01171     return;
01172   }
01173 
01174   font = pango_font_map_load_font(fontmap, context, aFontDesc);
01175   if (!font) {
01176     return;
01177   }
01178 
01179 #if XlibSpecificationRelease >= 6
01180   xom = XOpenOM (GDK_DISPLAY(), NULL, NULL, NULL);
01181   if (xom) {
01182     XOMCharSetList cslist;
01183     int n_encodings = 0;
01184     cslist.charset_count = 0;
01185     XGetOMValues (xom,
01186       XNRequiredCharSet, &cslist,
01187       NULL);
01188     n_encodings = cslist.charset_count;
01189     if (n_encodings) {
01190       char **xom_encodings = (char**) g_malloc (sizeof(char*) * n_encodings);
01191 
01192       for (i = 0; i < n_encodings; i++) {
01193         xom_encodings[i] = g_ascii_strdown (cslist.charset_list[i], -1);
01194       }
01195       count = pango_x_list_subfonts(font, xom_encodings, n_encodings,
01196             &subfont_ids, &subfont_charsets);
01197 
01198       for(i = 0; i < n_encodings; i++) {
01199         g_free (xom_encodings[i]);
01200       }
01201       g_free (xom_encodings);
01202     }
01203     XCloseOM (xom);
01204   }
01205 #endif
01206   if (count == 0) {
01207     count = pango_x_list_subfonts(font, encodings, G_N_ELEMENTS(encodings),
01208           &subfont_ids, &subfont_charsets);
01209   }
01210 
01211   for (i = 0; i < count; i++) {
01212     subfont = pango_x_font_subfont_xlfd(font, subfont_ids[i]);
01213     AppendFontFFREName(aFontName, subfont);
01214     g_free(subfont);
01215     aFontName.Append(PRUnichar(','));
01216   }
01217 
01218   spec = pango_font_description_to_string(aFontDesc);
01219 
01220   if (subfont_ids != NULL) {
01221     g_free(subfont_ids);
01222   }
01223   if (subfont_charsets != NULL) {
01224     g_free(subfont_charsets);
01225   }
01226   g_free(spec);
01227   g_object_unref(font);
01228 }
01229 #endif /* MOZ_WIDGET_GTK2 && MOZ_ENABLE_COREXFONTS */