Back to index

lightning-sunbird  0.9+nobinonly
nsCairoDeviceContext.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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  * mozilla.org.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Stuart Parmenter <pavlov@pavlov.net>
00024  *   Vladimir Vukicevic <vladimir@pobox.com>
00025  *   Joe Hewitt <hewitt@netscape.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * 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 "nsIServiceManager.h"
00042 
00043 #include "nsCairoDeviceContext.h"
00044 #include "nsCairoRenderingContext.h"
00045 #include "nsCairoSurfaceManager.h"
00046 
00047 #include "nsCOMPtr.h"
00048 #include "nsIView.h"
00049 
00050 #ifdef MOZ_ENABLE_GTK2
00051 #include <gtk/gtk.h>
00052 #include <gdk/gdkx.h>
00053 #include "nsFontMetricsUtils.h"
00054 #include "nsFont.h"
00055 
00056 #include <pango/pango.h>
00057 #include <pango/pangox.h>
00058 #include <pango/pango-fontmap.h>
00059 #endif
00060 
00061 class nsSystemFontsGTK {
00062 
00063   public:
00064     nsSystemFontsGTK(float aPixelsToTwips);
00065 
00066     const nsFont& GetDefaultFont() { return mDefaultFont; }
00067     const nsFont& GetMenuFont() { return mMenuFont; }
00068     const nsFont& GetFieldFont() { return mFieldFont; }
00069     const nsFont& GetButtonFont() { return mButtonFont; }
00070 
00071   private:
00072     nsresult GetSystemFontInfo(GtkWidget *aWidget, nsFont* aFont,
00073                                float aPixelsToTwips) const;
00074 
00075     /*
00076      * The following system font constants exist:
00077      *
00078      * css2: http://www.w3.org/TR/REC-CSS2/fonts.html#x27
00079      * eSystemFont_Caption, eSystemFont_Icon, eSystemFont_Menu,
00080      * eSystemFont_MessageBox, eSystemFont_SmallCaption,
00081      * eSystemFont_StatusBar,
00082      * // css3
00083      * eSystemFont_Window, eSystemFont_Document,
00084      * eSystemFont_Workspace, eSystemFont_Desktop,
00085      * eSystemFont_Info, eSystemFont_Dialog,
00086      * eSystemFont_Button, eSystemFont_PullDownMenu,
00087      * eSystemFont_List, eSystemFont_Field,
00088      * // moz
00089      * eSystemFont_Tooltips, eSystemFont_Widget
00090      */
00091     nsFont mDefaultFont;
00092     nsFont mButtonFont;
00093     nsFont mFieldFont;
00094     nsFont mMenuFont;
00095 };
00096 
00097 static nsSystemFontsGTK *gSystemFonts = nsnull;
00098 
00099 
00100 NS_IMPL_ISUPPORTS_INHERITED0(nsCairoDeviceContext, DeviceContextImpl)
00101 
00102 nsCairoDeviceContext::nsCairoDeviceContext()
00103 {
00104     NS_INIT_ISUPPORTS();
00105 
00106     mDevUnitsToAppUnits = 1.0f;
00107     mAppUnitsToDevUnits = 1.0f;
00108     mCPixelScale = 1.0f;
00109     mZoom = 1.0f;
00110 
00111 #ifdef MOZ_ENABLE_XLIB
00112     mXlibRgbHandle = xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE);
00113 #endif
00114 }
00115 
00116 nsCairoDeviceContext::~nsCairoDeviceContext()
00117 {
00118 }
00119 
00120 int
00121 helpful_error_handler (Display *dpy, XErrorEvent *error)
00122 {
00123     fprintf (stderr, "++++++++ X Error! serial %d code: %d request: %d minor: %d\n",
00124              error->serial, error->error_code, error->request_code, error->minor_code);
00125     return 0;
00126 }
00127 
00128 NS_IMETHODIMP
00129 nsCairoDeviceContext::Init(nsNativeWidget aWidget)
00130 {
00131     //DeviceContextImpl::CommonInit();
00132 
00133     mTwipsToPixels = 96 / (float)NSIntPointsToTwips(72);
00134     mPixelsToTwips = 1.0f / mTwipsToPixels;
00135 
00136     mWidget = aWidget;
00137 
00138     if (!mScreenManager)
00139         mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
00140     if (!mScreenManager)
00141         return NS_ERROR_FAILURE;
00142 
00143     nsCOMPtr<nsIScreen> screen;
00144     mScreenManager->GetPrimaryScreen (getter_AddRefs(screen));
00145     if (screen) {
00146         PRInt32 x, y, width, height;
00147         screen->GetRect (&x, &y, &width, &height );
00148         mWidthFloat = float(width);
00149         mHeightFloat = float(height);
00150     }
00151 
00152     if (getenv ("MOZ_X_SYNC")) {
00153         fprintf (stderr, "+++ Enabling XSynchronize\n");
00154         XSynchronize (gdk_x11_get_default_xdisplay(), True);
00155         XSetErrorHandler (helpful_error_handler);
00156     }
00157 
00158     mWidth = -1;
00159     mHeight = -1;
00160 
00161     return NS_OK;
00162 }
00163 
00164 NS_IMETHODIMP
00165 nsCairoDeviceContext::CreateRenderingContext(nsIView *aView,
00166                                              nsIRenderingContext *&aContext)
00167 {
00168     NS_ENSURE_ARG_POINTER(aView);
00169     NS_PRECONDITION(aView->HasWidget(), "View has no widget!");
00170 
00171     nsCOMPtr<nsIWidget> widget;
00172     widget = aView->GetWidget();
00173 
00174     return CreateRenderingContext(widget, aContext);
00175 }
00176 
00177 NS_IMETHODIMP
00178 nsCairoDeviceContext::CreateRenderingContext(nsIDrawingSurface *aSurface,
00179                                              nsIRenderingContext *&aContext)
00180 {
00181     nsresult rv;
00182 
00183     aContext = nsnull;
00184     nsCOMPtr<nsIRenderingContext> pContext;
00185     rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
00186     if (NS_SUCCEEDED(rv)) {
00187         rv = pContext->Init(this, aSurface);
00188         if (NS_SUCCEEDED(rv)) {
00189             aContext = pContext;
00190             NS_ADDREF(aContext);
00191         }
00192     }
00193 
00194     return rv;
00195 }
00196 
00197 NS_IMETHODIMP
00198 nsCairoDeviceContext::CreateRenderingContext(nsIWidget *aWidget,
00199                                              nsIRenderingContext *&aContext)
00200 {
00201     nsresult rv;
00202 
00203     aContext = nsnull;
00204     nsCOMPtr<nsIRenderingContext> pContext;
00205     rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
00206     if (NS_SUCCEEDED(rv)) {
00207         rv = pContext->Init(this, aWidget);
00208         if (NS_SUCCEEDED(rv)) {
00209             aContext = pContext;
00210             NS_ADDREF(aContext);
00211         }
00212     }
00213 
00214     return rv;
00215 }
00216 
00217 NS_IMETHODIMP
00218 nsCairoDeviceContext::CreateRenderingContext(nsIRenderingContext *&aContext)
00219 {
00220     NS_ERROR("CreateRenderingContext with other rendering context arg; fix this if this needs to be called");
00221     return NS_OK;
00222 }
00223 
00224 NS_IMETHODIMP
00225 nsCairoDeviceContext::CreateRenderingContextInstance(nsIRenderingContext *&aContext)
00226 {
00227     nsCOMPtr<nsIRenderingContext> renderingContext = new nsCairoRenderingContext();
00228     if (!renderingContext)
00229         return NS_ERROR_OUT_OF_MEMORY;
00230 
00231     aContext = renderingContext;
00232     NS_ADDREF(aContext);
00233 
00234     return NS_OK;
00235 }
00236 
00237 NS_IMETHODIMP
00238 nsCairoDeviceContext::SupportsNativeWidgets(PRBool &aSupportsWidgets)
00239 {
00240     aSupportsWidgets = PR_TRUE;
00241     return NS_OK;
00242 }
00243 
00244 NS_IMETHODIMP
00245 nsCairoDeviceContext::GetScrollBarDimensions(float &aWidth, float &aHeight) const
00246 {
00247     aWidth = 10.0f * mPixelsToTwips;
00248     aHeight = 10.0f * mPixelsToTwips;
00249     return NS_OK;
00250 }
00251 
00252 NS_IMETHODIMP
00253 nsCairoDeviceContext::GetSystemFont(nsSystemFontID aID, nsFont *aFont) const
00254 {
00255     nsresult status = NS_OK;
00256 
00257     if (!gSystemFonts) {
00258         gSystemFonts = new nsSystemFontsGTK(mPixelsToTwips);
00259     }
00260 
00261     switch (aID) {
00262     case eSystemFont_Menu:         // css2
00263     case eSystemFont_PullDownMenu: // css3
00264         *aFont = gSystemFonts->GetMenuFont();
00265         break;
00266 
00267     case eSystemFont_Field:        // css3
00268     case eSystemFont_List:         // css3
00269         *aFont = gSystemFonts->GetFieldFont();
00270         break;
00271 
00272     case eSystemFont_Button:       // css3
00273         *aFont = gSystemFonts->GetButtonFont();
00274         break;
00275 
00276     case eSystemFont_Caption:      // css2
00277     case eSystemFont_Icon:         // css2
00278     case eSystemFont_MessageBox:   // css2
00279     case eSystemFont_SmallCaption: // css2
00280     case eSystemFont_StatusBar:    // css2
00281     case eSystemFont_Window:       // css3
00282     case eSystemFont_Document:     // css3
00283     case eSystemFont_Workspace:    // css3
00284     case eSystemFont_Desktop:      // css3
00285     case eSystemFont_Info:         // css3
00286     case eSystemFont_Dialog:       // css3
00287     case eSystemFont_Tooltips:     // moz
00288     case eSystemFont_Widget:       // moz
00289         *aFont = gSystemFonts->GetDefaultFont();
00290         break;
00291     }
00292 
00293     return status;
00294 }
00295 
00296 NS_IMETHODIMP
00297 nsCairoDeviceContext::CheckFontExistence(const nsString& aFaceName)
00298 {
00299     return NS_OK;
00300 }
00301 
00302 NS_IMETHODIMP
00303 nsCairoDeviceContext::GetDepth(PRUint32& aDepth)
00304 {
00305     aDepth = 24;
00306     return NS_OK;
00307 }
00308 
00309 
00310 NS_IMETHODIMP
00311 nsCairoDeviceContext::GetPaletteInfo(nsPaletteInfo& aPaletteInfo)
00312 {
00313     aPaletteInfo.isPaletteDevice = PR_FALSE;
00314     aPaletteInfo.sizePalette = 0;
00315     aPaletteInfo.numReserved = 0;
00316     aPaletteInfo.palette = nsnull;
00317     return NS_OK;
00318 }
00319 
00320 
00321 NS_IMETHODIMP
00322 nsCairoDeviceContext::ConvertPixel(nscolor aColor, PRUint32 & aPixel)
00323 {
00324     aPixel = aColor;
00325     return NS_OK;
00326 }
00327 
00328 
00329 NS_IMETHODIMP
00330 nsCairoDeviceContext::GetDeviceSurfaceDimensions(PRInt32 &aWidth, PRInt32 &aHeight)
00331 {
00332     if (mWidth == -1)
00333         mWidth = NSToIntRound(mWidthFloat * mDevUnitsToAppUnits);
00334 
00335     if (mHeight == -1)
00336         mHeight = NSToIntRound(mHeightFloat * mDevUnitsToAppUnits);
00337 
00338     aWidth = mWidth;
00339     aHeight = mHeight;
00340 
00341     return NS_OK;
00342 }
00343 
00344 
00345 NS_IMETHODIMP
00346 nsCairoDeviceContext::GetRect(nsRect &aRect)
00347 {
00348 #if defined (MOZ_ENABLE_GTK2) || defined (MOZ_ENABLE_XLIB)
00349     if (mWidget) {
00350         Window root_ignore;
00351         int x, y;
00352         unsigned int bwidth_ignore, width, height, depth;
00353 
00354         XGetGeometry(GDK_WINDOW_XDISPLAY(GDK_DRAWABLE(mWidget)),
00355                      GDK_WINDOW_XWINDOW(GDK_DRAWABLE(mWidget)),
00356                      &root_ignore, &x, &y,
00357                      &width, &height,
00358                      &bwidth_ignore, &depth);
00359 
00360         nsCOMPtr<nsIScreen> screen;
00361         mScreenManager->ScreenForRect(x, y, width, height, getter_AddRefs(screen));
00362         screen->GetRect(&aRect.x, &aRect.y, &aRect.width, &aRect.height);
00363 
00364         aRect.x = NSToIntRound(mDevUnitsToAppUnits * aRect.x);
00365         aRect.y = NSToIntRound(mDevUnitsToAppUnits * aRect.y);
00366         aRect.width = NSToIntRound(mDevUnitsToAppUnits * aRect.width);
00367         aRect.height = NSToIntRound(mDevUnitsToAppUnits * aRect.height);
00368     } else {
00369         aRect.x = 0;
00370         aRect.y = 0;
00371 
00372         this->GetDeviceSurfaceDimensions(aRect.width, aRect.height);
00373     }
00374 #else
00375 #error write me
00376 #endif
00377 
00378     fprintf (stderr, "+++ GetRect: %d %d %d %d\n", aRect.x, aRect.y, aRect.width, aRect.height);
00379 
00380     return NS_OK;
00381 }
00382 
00383 
00384 NS_IMETHODIMP
00385 nsCairoDeviceContext::GetClientRect(nsRect &aRect)
00386 {
00387     fprintf (stderr, "+++ GetClientRect: ");
00388     nsresult rv = this->GetRect(aRect);
00389     return rv;
00390 }
00391 
00392 /*
00393  * below methods are for printing and are not implemented
00394  */
00395 NS_IMETHODIMP
00396 nsCairoDeviceContext::GetDeviceContextFor(nsIDeviceContextSpec *aDevice,
00397                                           nsIDeviceContext *&aContext)
00398 {
00399     /* we don't do printing */
00400     return NS_ERROR_NOT_IMPLEMENTED;
00401 }
00402 
00403 
00404 NS_IMETHODIMP
00405 nsCairoDeviceContext::PrepareDocument(PRUnichar * aTitle, 
00406                                       PRUnichar*  aPrintToFileName)
00407 {
00408     return NS_OK;
00409 }
00410 
00411 
00412 NS_IMETHODIMP
00413 nsCairoDeviceContext::BeginDocument(PRUnichar*  aTitle, 
00414                                             PRUnichar*  aPrintToFileName,
00415                                             PRInt32     aStartPage, 
00416                                             PRInt32     aEndPage)
00417 {
00418     return NS_OK;
00419 }
00420 
00421 
00422 NS_IMETHODIMP
00423 nsCairoDeviceContext::EndDocument(void)
00424 {
00425     return NS_OK;
00426 }
00427 
00428 
00429 NS_IMETHODIMP
00430 nsCairoDeviceContext::AbortDocument(void)
00431 {
00432     return NS_OK;
00433 }
00434 
00435 
00436 NS_IMETHODIMP
00437 nsCairoDeviceContext::BeginPage(void)
00438 {
00439     return NS_OK;
00440 }
00441 
00442 
00443 NS_IMETHODIMP
00444 nsCairoDeviceContext::EndPage(void)
00445 {
00446     return NS_OK;
00447 }
00448 
00449 
00450 NS_IMETHODIMP
00451 nsCairoDeviceContext::SetAltDevice(nsIDeviceContext* aAltDC)
00452 {
00453     return NS_OK;
00454 }
00455 
00456 
00457 NS_IMETHODIMP
00458 nsCairoDeviceContext::GetAltDevice(nsIDeviceContext** aAltDC)
00459 {
00460     *aAltDC = nsnull;
00461     return NS_OK;
00462 }
00463 
00464 
00465 NS_IMETHODIMP
00466 nsCairoDeviceContext::SetUseAltDC(PRUint8 aValue, PRBool aOn)
00467 {
00468     return NS_OK;
00469 }
00470 
00471 #if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB)
00472 Display *
00473 nsCairoDeviceContext::GetXDisplay()
00474 {
00475 #ifdef MOZ_ENABLE_GTK2
00476     return gdk_x11_get_default_xdisplay();
00477 #endif
00478 }
00479 
00480 Visual *
00481 nsCairoDeviceContext::GetXVisual()
00482 {
00483     return DefaultVisual(GetXDisplay(),DefaultScreen(GetXDisplay()));
00484 }
00485 
00486 Colormap
00487 nsCairoDeviceContext::GetXColormap()
00488 {
00489     return DefaultColormap(GetXDisplay(),DefaultScreen(GetXDisplay()));
00490 }
00491 
00492 Drawable
00493 nsCairoDeviceContext::GetXPixmapParentDrawable()
00494 {
00495     return RootWindow(GetXDisplay(),DefaultScreen(GetXDisplay()));
00496 }
00497 
00498 #endif
00499 
00500 
00501 
00502 PRInt32 GetXftDPI(void);
00503 
00504 #define DEFAULT_TWIP_FONT_SIZE 240
00505 
00506 nsSystemFontsGTK::nsSystemFontsGTK(float aPixelsToTwips)
00507   : mDefaultFont("sans-serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
00508                  NS_FONT_WEIGHT_NORMAL, NS_FONT_DECORATION_NONE,
00509                  DEFAULT_TWIP_FONT_SIZE),
00510     mButtonFont("sans-serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
00511                 NS_FONT_WEIGHT_NORMAL, NS_FONT_DECORATION_NONE,
00512                 DEFAULT_TWIP_FONT_SIZE),
00513     mFieldFont("sans-serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
00514                NS_FONT_WEIGHT_NORMAL, NS_FONT_DECORATION_NONE,
00515                DEFAULT_TWIP_FONT_SIZE),
00516     mMenuFont("sans-serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
00517                NS_FONT_WEIGHT_NORMAL, NS_FONT_DECORATION_NONE,
00518                DEFAULT_TWIP_FONT_SIZE)
00519 {
00520   /*
00521    * Much of the widget creation code here is similar to the code in
00522    * nsLookAndFeel::InitColors().
00523    */
00524 
00525   // mDefaultFont
00526   GtkWidget *label = gtk_label_new("M");
00527   GtkWidget *parent = gtk_fixed_new();
00528   GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
00529 
00530   gtk_container_add(GTK_CONTAINER(parent), label);
00531   gtk_container_add(GTK_CONTAINER(window), parent);
00532 
00533   gtk_widget_ensure_style(label);
00534 
00535   GetSystemFontInfo(label, &mDefaultFont, aPixelsToTwips);
00536 
00537   gtk_widget_destroy(window);  // no unref, windows are different
00538 
00539   // mFieldFont
00540   GtkWidget *entry = gtk_entry_new();
00541   parent = gtk_fixed_new();
00542   window = gtk_window_new(GTK_WINDOW_POPUP);
00543 
00544   gtk_container_add(GTK_CONTAINER(parent), entry);
00545   gtk_container_add(GTK_CONTAINER(window), parent);
00546   gtk_widget_ensure_style(entry);
00547 
00548   GetSystemFontInfo(entry, &mFieldFont, aPixelsToTwips);
00549 
00550   gtk_widget_destroy(window);  // no unref, windows are different
00551 
00552   // mMenuFont
00553   GtkWidget *accel_label = gtk_accel_label_new("M");
00554   GtkWidget *menuitem = gtk_menu_item_new();
00555   GtkWidget *menu = gtk_menu_new();
00556   gtk_object_ref(GTK_OBJECT(menu));
00557   gtk_object_sink(GTK_OBJECT(menu));
00558 
00559   gtk_container_add(GTK_CONTAINER(menuitem), accel_label);
00560   gtk_menu_append(GTK_MENU(menu), menuitem);
00561 
00562   gtk_widget_ensure_style(accel_label);
00563 
00564   GetSystemFontInfo(accel_label, &mMenuFont, aPixelsToTwips);
00565 
00566   gtk_widget_unref(menu);
00567 
00568   // mButtonFont
00569   parent = gtk_fixed_new();
00570   GtkWidget *button = gtk_button_new();
00571   label = gtk_label_new("M");
00572   window = gtk_window_new(GTK_WINDOW_POPUP);
00573           
00574   gtk_container_add(GTK_CONTAINER(button), label);
00575   gtk_container_add(GTK_CONTAINER(parent), button);
00576   gtk_container_add(GTK_CONTAINER(window), parent);
00577 
00578   gtk_widget_ensure_style(label);
00579 
00580   GetSystemFontInfo(label, &mButtonFont, aPixelsToTwips);
00581 
00582   gtk_widget_destroy(window);  // no unref, windows are different
00583 
00584 }
00585 
00586 #if 0 // debugging code to list the font properties
00587 static void
00588 ListFontProps(XFontStruct *aFont, Display *aDisplay)
00589 {
00590   printf("\n\n");
00591   for (int i = 0, n = aFont->n_properties; i < n; ++i) {
00592     XFontProp *prop = aFont->properties + i;
00593     char *atomName = ::XGetAtomName(aDisplay, prop->name);
00594     // 500 is just a guess
00595     char *cardName = (prop->card32 > 0 && prop->card32 < 500)
00596                        ? ::XGetAtomName(aDisplay, prop->card32)
00597                        : 0;
00598     printf("%s : %ld (%s)\n", atomName, prop->card32, cardName?cardName:"");
00599     ::XFree(atomName);
00600     if (cardName)
00601       ::XFree(cardName);
00602   }
00603   printf("\n\n");
00604 }
00605 #endif
00606 
00607 #if defined(MOZ_ENABLE_COREXFONTS) || defined(MOZ_WIDGET_GTK)
00608 
00609 #define LOCATE_MINUS(pos, str)  { \
00610    pos = str.FindChar('-'); \
00611    if (pos < 0) \
00612      return ; \
00613   }
00614 #define NEXT_MINUS(pos, str) { \
00615    pos = str.FindChar('-', pos+1); \
00616    if (pos < 0) \
00617      return ; \
00618   }  
00619 
00620 static void
00621 AppendFontFFREName(nsString& aString, const char* aXLFDName)
00622 {
00623   // convert fontname from XFLD to FFRE and append, ie. from
00624   // -adobe-courier-medium-o-normal--14-140-75-75-m-90-iso8859-15
00625   // to
00626   // adobe-courier-iso8859-15
00627   nsCAutoString nameStr(aXLFDName);
00628   PRInt32 pos1, pos2;
00629   // remove first '-' and everything before it. 
00630   LOCATE_MINUS(pos1, nameStr);
00631   nameStr.Cut(0, pos1+1);
00632 
00633   // skip foundry and family name
00634   LOCATE_MINUS(pos1, nameStr);
00635   NEXT_MINUS(pos1, nameStr);
00636   pos2 = pos1;
00637 
00638   // find '-' just before charset registry
00639   for (PRInt32 i=0; i < 10; i++) {
00640     NEXT_MINUS(pos2, nameStr);
00641   }
00642 
00643   // remove everything in between
00644   nameStr.Cut(pos1, pos2-pos1);
00645 
00646   aString.AppendWithConversion(nameStr.get());
00647 }
00648 #endif /* MOZ_ENABLE_COREXFONTS || MOZ_WIDGET_GTK*/
00649 
00650 #ifdef MOZ_WIDGET_GTK
00651 static void
00652 AppendFontName(XFontStruct* aFontStruct, nsString& aString, Display *aDisplay)
00653 {
00654   unsigned long pr = 0;
00655   // we first append the FFRE name to reconstruct font more faithfully
00656   unsigned long font_atom = gdk_atom_intern("FONT", FALSE);
00657   if (::XGetFontProperty(aFontStruct, font_atom, &pr) && pr) {
00658     char* xlfdName = ::XGetAtomName(aDisplay, pr);
00659     AppendFontFFREName(aString, xlfdName);
00660     ::XFree(xlfdName);
00661   }
00662  
00663   aString.Append(PRUnichar(','));
00664 
00665   // next, we need to append family name to cover more encodings.
00666   if ((::XGetFontProperty(aFontStruct, XA_FAMILY_NAME, &pr) ||
00667        ::XGetFontProperty(aFontStruct, XA_FULL_NAME, &pr)) &&
00668       pr) {
00669     char *fontName = ::XGetAtomName(aDisplay, pr);
00670     aString.AppendWithConversion(fontName);
00671     ::XFree(fontName);
00672   }
00673 }
00674 
00675 static PRUint16
00676 GetFontWeight(XFontStruct* aFontStruct, Display *aDisplay)
00677 {
00678   PRUint16 weight = NS_FONT_WEIGHT_NORMAL;
00679 
00680   // WEIGHT_NAME seems more reliable than WEIGHT, where 10 can mean
00681   // anything.  Check both, and make it bold if either says so.
00682   unsigned long pr = 0;
00683   Atom weightName = ::XInternAtom(aDisplay, "WEIGHT_NAME", True);
00684   if (weightName != None) {
00685     if (::XGetFontProperty(aFontStruct, weightName, &pr) && pr) {
00686       char *weightString = ::XGetAtomName(aDisplay, pr);
00687       if (nsCRT::strcasecmp(weightString, "bold") == 0)
00688         weight = NS_FONT_WEIGHT_BOLD;
00689       ::XFree(weightString);
00690     }
00691   }
00692 
00693   pr = 0;
00694   if (::XGetFontProperty(aFontStruct, XA_WEIGHT, &pr) && pr > 10 )
00695     weight = NS_FONT_WEIGHT_BOLD;
00696 
00697   return weight;
00698 }
00699 
00700 static nscoord
00701 GetFontSize(XFontStruct *aFontStruct, float aPixelsToTwips)
00702 {
00703   unsigned long pr = 0;
00704   Atom pixelSizeAtom = ::XInternAtom(GDK_DISPLAY(), "PIXEL_SIZE", 0);
00705   if (!::XGetFontProperty(aFontStruct, pixelSizeAtom, &pr) || !pr)
00706     return DEFAULT_TWIP_FONT_SIZE;
00707   return NSIntPixelsToTwips(pr, aPixelsToTwips);
00708 }
00709 
00710 nsresult
00711 nsSystemFontsGTK::GetSystemFontInfo(GtkWidget *aWidget, nsFont* aFont,
00712                                     float aPixelsToTwips) const
00713 {
00714   GtkStyle *style = gtk_widget_get_style(aWidget);
00715 
00716   GdkFont *theFont = style->font;
00717 
00718   aFont->style       = NS_FONT_STYLE_NORMAL;
00719   aFont->weight      = NS_FONT_WEIGHT_NORMAL;
00720   aFont->decorations = NS_FONT_DECORATION_NONE;
00721   
00722   // do we have the default_font defined by GTK/GDK then
00723   // we use it, if not then we load helvetica, if not then
00724   // we load fixed font else we error out.
00725   if (!theFont)
00726     theFont = default_font; // GTK default font
00727 
00728   if (!theFont)
00729     theFont = ::gdk_font_load( GDK_DEFAULT_FONT1 );
00730   
00731   if (!theFont)
00732     theFont = ::gdk_font_load( GDK_DEFAULT_FONT2 );
00733   
00734   if (!theFont)
00735     return NS_ERROR_FAILURE;
00736 
00737   Display *fontDisplay = GDK_FONT_XDISPLAY(theFont);
00738   if (theFont->type == GDK_FONT_FONT) {
00739     XFontStruct *fontStruct =
00740         NS_STATIC_CAST(XFontStruct*, GDK_FONT_XFONT(theFont));
00741 
00742     aFont->name.Truncate();
00743     AppendFontName(fontStruct, aFont->name, fontDisplay);
00744     aFont->weight = GetFontWeight(fontStruct, fontDisplay);
00745     aFont->size = GetFontSize(fontStruct, aPixelsToTwips);
00746   } else {
00747     NS_ASSERTION(theFont->type == GDK_FONT_FONTSET,
00748                  "theFont->type can only have two values");
00749 
00750     XFontSet fontSet = NS_REINTERPRET_CAST(XFontSet, GDK_FONT_XFONT(theFont));
00751     XFontStruct **fontStructs;
00752     char **fontNames;
00753     int numFonts = ::XFontsOfFontSet(fontSet, &fontStructs, &fontNames);
00754     if (numFonts == 0)
00755       return NS_ERROR_FAILURE;
00756 
00757     // Use the weight and size from the first font, but append all
00758     // the names.
00759     aFont->weight = GetFontWeight(*fontStructs, fontDisplay);
00760     aFont->size = GetFontSize(*fontStructs, aPixelsToTwips);
00761     nsString& fontName = aFont->name;
00762     fontName.Truncate();
00763     for (;;) {
00764       // we need to append FFRE name instead of family name in this case
00765       AppendFontFFREName(fontName, *fontNames);
00766       ++fontNames;
00767       --numFonts;
00768       if (numFonts == 0)
00769         break;
00770       fontName.Append(PRUnichar(','));
00771     }
00772   }
00773   return NS_OK;
00774 }
00775 #endif /* MOZ_WIDGET_GTK */
00776 
00777 #ifdef MOZ_WIDGET_GTK2
00778 
00779 #ifdef MOZ_ENABLE_COREXFONTS
00780 static void xlfd_from_pango_font_description(GtkWidget *aWidget,
00781                                              const PangoFontDescription *aFontDesc,
00782                                              nsString& aFontName);
00783 #endif /* MOZ_ENABLE_COREXFONTS */
00784 
00785 nsresult
00786 nsSystemFontsGTK::GetSystemFontInfo(GtkWidget *aWidget, nsFont* aFont,
00787                                     float aPixelsToTwips) const
00788 {
00789   GtkSettings *settings = gtk_widget_get_settings(aWidget);
00790 
00791   aFont->style       = NS_FONT_STYLE_NORMAL;
00792   aFont->decorations = NS_FONT_DECORATION_NONE;
00793 
00794   gchar *fontname;
00795   g_object_get(settings, "gtk-font-name", &fontname, NULL);
00796 
00797   PangoFontDescription *desc;
00798   desc = pango_font_description_from_string(fontname);
00799 
00800   aFont->systemFont = PR_TRUE;
00801 
00802   g_free(fontname);
00803 
00804   aFont->name.Truncate();
00805 #ifdef MOZ_ENABLE_XFT
00806   if (NS_IsXftEnabled()) {
00807     aFont->name.Assign(PRUnichar('"'));
00808     aFont->name.AppendWithConversion(pango_font_description_get_family(desc));
00809     aFont->name.Append(PRUnichar('"'));
00810   }
00811 #endif /* MOZ_ENABLE_XFT */
00812 
00813 #ifdef MOZ_ENABLE_COREXFONTS
00814   // if name already set by Xft, do nothing
00815   if (!aFont->name.Length()) {
00816     xlfd_from_pango_font_description(aWidget, desc, aFont->name);
00817   }
00818 #endif /* MOZ_ENABLE_COREXFONTS */
00819   aFont->weight = pango_font_description_get_weight(desc);
00820 
00821   float size = float(pango_font_description_get_size(desc) / PANGO_SCALE);
00822 #ifdef MOZ_ENABLE_XFT
00823   if (NS_IsXftEnabled()) {
00824     PRInt32 dpi = GetXftDPI();
00825     if (dpi != 0) {
00826       // pixels/inch * twips/pixel * inches/twip == 1, except it isn't, since
00827       // our idea of dpi may be different from Xft's.
00828       size *= float(dpi) * aPixelsToTwips * (1.0f/1440.0f);
00829     }
00830   }
00831 #endif /* MOZ_ENABLE_XFT */
00832   aFont->size = NSFloatPointsToTwips(size);
00833   
00834   pango_font_description_free(desc);
00835 
00836   return NS_OK;
00837 }
00838 #endif /* MOZ_WIDGET_GTK2 */
00839 
00840 #ifdef MOZ_WIDGET_GTK
00841 /* static */
00842 PRInt32
00843 GetOSDPI(void)
00844 {
00845 
00846 #ifdef MOZ_ENABLE_XFT
00847   // try to get it from xft
00848   if (NS_IsXftEnabled()) {
00849     PRInt32 xftdpi = GetXftDPI();
00850     if (xftdpi)
00851       return xftdpi;
00852   }
00853 #endif /* MOZ_ENABLE_XFT */
00854 
00855   // Set OSVal to what the operating system thinks the logical resolution is.
00856   float screenWidthIn = float(::gdk_screen_width_mm()) / 25.4f;
00857   return NSToCoordRound(float(::gdk_screen_width()) / screenWidthIn);
00858 }
00859 #endif /* MOZ_WIDGET_GTK */
00860 
00861 #ifdef MOZ_WIDGET_GTK2
00862 /* static */
00863 PRInt32
00864 GetOSDPI(void)
00865 {
00866   GtkSettings *settings = gtk_settings_get_default();
00867 
00868   // first try to get the gtk2 dpi
00869   gint dpi = 0;
00870 
00871   // See if there's a gtk-xft-dpi object on the settings object - note
00872   // that we don't have to free the spec since it isn't addrefed
00873   // before being returned.  It's just part of an internal object.
00874   // The gtk-xft-dpi setting is included in rh8 and might be included
00875   // in later versions of gtk, so we conditionally check for it.
00876   GParamSpec *spec;
00877   spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(settings)),
00878                                       "gtk-xft-dpi");
00879   if (spec) {
00880     g_object_get(G_OBJECT(settings),
00881                  "gtk-xft-dpi", &dpi,
00882                  NULL);
00883   }
00884 
00885   if (dpi > 0)
00886     return NSToCoordRound(dpi / 1024.0);
00887 
00888 #ifdef MOZ_ENABLE_XFT
00889   // try to get it from xft
00890   PRInt32 xftdpi = GetXftDPI();
00891 
00892   if (xftdpi)
00893     return xftdpi;
00894 #endif /* MOZ_ENABLE_XFT */
00895   
00896   // fall back to the physical resolution
00897   float screenWidthIn = float(::gdk_screen_width_mm()) / 25.4f;
00898   return NSToCoordRound(float(::gdk_screen_width()) / screenWidthIn);
00899 }
00900 #endif /* MOZ_WIDGET_GTK2 */
00901 
00902 #ifdef MOZ_ENABLE_XFT
00903 /* static */
00904 PRInt32
00905 GetXftDPI(void)
00906 {
00907   char *val = XGetDefault(GDK_DISPLAY(), "Xft", "dpi");
00908   if (val) {
00909     char *e;
00910     double d = strtod(val, &e);
00911 
00912     if (e != val)
00913       return NSToCoordRound(d);
00914   }
00915 
00916   return 0;
00917 }
00918 #endif /* MOZ_ENABLE_XFT */
00919 
00920 #if defined(MOZ_WIDGET_GTK2) && defined(MOZ_ENABLE_COREXFONTS)
00921 // xlfd_from_pango_font_description copied from vte, which was
00922 // written by nalin@redhat.com, and added some codes.
00923 static void
00924 xlfd_from_pango_font_description(GtkWidget *aWidget,
00925          const PangoFontDescription *aFontDesc,
00926                                  nsString& aFontName)
00927 {
00928   char *spec;
00929   PangoContext *context;
00930   PangoFont *font;
00931   PangoXSubfont *subfont_ids;
00932   PangoFontMap *fontmap;
00933   int *subfont_charsets, i, count = 0;
00934   char *subfont;
00935   char *encodings[] = {
00936     "ascii-0",
00937     "big5-0",
00938     "dos-437",
00939     "dos-737",
00940     "gb18030.2000-0",
00941     "gb18030.2000-1",
00942     "gb2312.1980-0",
00943     "iso8859-1",
00944     "iso8859-2",
00945     "iso8859-3",
00946     "iso8859-4",
00947     "iso8859-5",
00948     "iso8859-7",
00949     "iso8859-8",
00950     "iso8859-9",
00951     "iso8859-10",
00952     "iso8859-15",
00953     "iso10646-0",
00954     "iso10646-1",
00955     "jisx0201.1976-0",
00956     "jisx0208.1983-0",
00957     "jisx0208.1990-0",
00958     "jisx0208.1997-0",
00959     "jisx0212.1990-0",
00960     "jisx0213.2000-1",
00961     "jisx0213.2000-2",
00962     "koi8-r",
00963     "koi8-u",
00964     "koi8-ub",
00965     "ksc5601.1987-0",
00966     "ksc5601.1992-3",
00967     "tis620-0",
00968     "iso8859-13",
00969     "microsoft-cp1251"
00970     "misc-fontspecific",
00971   };
00972 #if XlibSpecificationRelease >= 6
00973   XOM xom;
00974 #endif
00975   if (!aFontDesc) {
00976     return;
00977   }
00978 
00979   context = gtk_widget_get_pango_context(GTK_WIDGET(aWidget));
00980 
00981   pango_context_set_language (context, gtk_get_default_language ());
00982   fontmap = pango_x_font_map_for_display(GDK_DISPLAY());
00983 
00984   if (!fontmap) {
00985     return;
00986   }
00987 
00988   font = pango_font_map_load_font(fontmap, context, aFontDesc);
00989   if (!font) {
00990     return;
00991   }
00992 
00993 #if XlibSpecificationRelease >= 6
00994   xom = XOpenOM (GDK_DISPLAY(), NULL, NULL, NULL);
00995   if (xom) {
00996     XOMCharSetList cslist;
00997     int n_encodings = 0;
00998     cslist.charset_count = 0;
00999     XGetOMValues (xom,
01000       XNRequiredCharSet, &cslist,
01001       NULL);
01002     n_encodings = cslist.charset_count;
01003     if (n_encodings) {
01004       char **xom_encodings = (char**) g_malloc (sizeof(char*) * n_encodings);
01005 
01006       for (i = 0; i < n_encodings; i++) {
01007         xom_encodings[i] = g_ascii_strdown (cslist.charset_list[i], -1);
01008       }
01009       count = pango_x_list_subfonts(font, xom_encodings, n_encodings,
01010             &subfont_ids, &subfont_charsets);
01011 
01012       for(i = 0; i < n_encodings; i++) {
01013         g_free (xom_encodings[i]);
01014       }
01015       g_free (xom_encodings);
01016     }
01017     XCloseOM (xom);
01018   }
01019 #endif
01020   if (count == 0) {
01021     count = pango_x_list_subfonts(font, encodings, G_N_ELEMENTS(encodings),
01022           &subfont_ids, &subfont_charsets);
01023   }
01024 
01025   for (i = 0; i < count; i++) {
01026     subfont = pango_x_font_subfont_xlfd(font, subfont_ids[i]);
01027     AppendFontFFREName(aFontName, subfont);
01028     g_free(subfont);
01029     aFontName.Append(PRUnichar(','));
01030   }
01031 
01032   spec = pango_font_description_to_string(aFontDesc);
01033 
01034   if (subfont_ids != NULL) {
01035     g_free(subfont_ids);
01036   }
01037   if (subfont_charsets != NULL) {
01038     g_free(subfont_charsets);
01039   }
01040   g_free(spec);
01041 }
01042 #endif /* MOZ_WIDGET_GTK2 && MOZ_ENABLE_COREXFONTS */