Back to index

lightning-sunbird  0.9+nobinonly
nsFontMetricsXft.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org code.
00018  *
00019  * The Initial Developer of the Original Code is Christopher Blizzard
00020  * <blizzard@mozilla.org>.  Portions created by the Initial Developer
00021  * are Copyright (C) 2002 the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Pierre Phaneuf <pp@ludusdesign.com> 
00025  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00026  *   Brian Stell <bstell@ix.netcom.com>
00027  *   Morten Nilsen <morten@nilsen.com>
00028  *   Jungshik Shin <jshin@mailaps.org>
00029  *   Jim Nance <jim_nance@yahoo.com>
00030  *
00031  * Alternatively, the contents of this file may be used under the terms of
00032  * either the GNU General Public License Version 2 or later (the "GPL"), or
00033  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00034  * in which case the provisions of the GPL or the LGPL are applicable instead
00035  * of those above. If you wish to allow use of your version of this file only
00036  * under the terms of either the GPL or the LGPL, and not to allow others to
00037  * use your version of this file under the terms of the MPL, indicate your
00038  * decision by deleting the provisions above and replace them with the notice
00039  * and other provisions required by the GPL or the LGPL. If you do not delete
00040  * the provisions above, a recipient may use your version of this file under
00041  * the terms of any one of the MPL, the GPL or the LGPL.
00042  *
00043  * ***** END LICENSE BLOCK ***** */
00044 
00045 #include "nsISupportsUtils.h"
00046 #include "nsServiceManagerUtils.h"
00047 #include "nsIPref.h"
00048 #include "nsFontMetricsXft.h"
00049 #include "prenv.h"
00050 #include "prprf.h"
00051 #include "prlink.h"
00052 #include "nsQuickSort.h"
00053 #include "nsFont.h"
00054 #include "nsIDeviceContext.h"
00055 #include "nsCairoRenderingContext.h"
00056 #include "nsCairoDrawingSurface.h"
00057 #include "nsReadableUtils.h"
00058 #include "nsUnicharUtils.h"
00059 #include "nsITimelineService.h"
00060 #include "nsICharsetConverterManager.h"
00061 #include "nsICharRepresentable.h"
00062 #include "nsIPersistentProperties2.h"
00063 #include "nsCompressedCharMap.h"
00064 #include "nsNetUtil.h"
00065 #include "nsClassHashtable.h"
00066 #include "nsAutoBuffer.h"
00067 #include "nsFontConfigUtils.h"
00068 
00069 #include <gdk/gdkx.h>
00070 #include <freetype/tttables.h>
00071 #include <freetype/freetype.h>
00072 
00073 #define FORCE_PR_LOG
00074 #include "prlog.h"
00075 
00076 // Abstract class nsFontXft is the base class for nsFontXftUnicode and
00077 // nsFontXftCustom, either of which is an instance of fonts.  The 
00078 // |nsFontMetricsXft| class is made up of a collection of these little 
00079 // fonts, really.
00080 
00081 class nsAutoDrawSpecBuffer;
00082 
00083 class nsFontXft {
00084 public:
00085     nsFontXft(FcPattern *aPattern, FcPattern *aFontName);
00086     virtual ~nsFontXft() = 0;
00087 
00088     // Callers outside of FindFont and DoMatch (which deal directly with
00089     // mLoadedFonts) do not need to call this; they can access mXftFont
00090     // directly since it is guaranteed to be non-null.
00091     XftFont   *GetXftFont (void);
00092     virtual nsresult GetTextExtents32 (const FcChar32 *aString, PRUint32 aLen, 
00093                                        XGlyphInfo &aGlyphInfo);
00094     gint     GetWidth32               (const FcChar32 *aString, PRUint32 aLen);
00095 
00096 #ifdef MOZ_MATHML
00097     nsresult GetBoundingMetrics32 (const FcChar32 *aString, 
00098                                    PRUint32 aLength,
00099                                    nsBoundingMetrics &aBoundingMetrics);
00100 #endif /* MOZ_MATHML */
00101 
00102     PRInt16    GetMaxAscent(void);
00103     PRInt16    GetMaxDescent(void);
00104 
00105     virtual PRBool     HasChar(PRUint32 aChar) = 0;
00106     virtual FT_UInt    CharToGlyphIndex(FcChar32 aChar);
00107 
00108     virtual nsresult   DrawStringSpec(FcChar32* aString, PRUint32 aLen,
00109                                       void *aData);
00110                                       
00111     // a reference to the font loaded and information about it.  
00112     XftFont   *mXftFont;
00113     FcPattern *mPattern;
00114     FcPattern *mFontName;
00115     FcCharSet *mCharset;
00116 };
00117 
00118 class nsFontXftInfo;
00119 
00120 // class for regular 'Unicode' fonts that are actually what they claim to be. 
00121 class nsFontXftUnicode : public nsFontXft {
00122 public:
00123     nsFontXftUnicode(FcPattern *aPattern, FcPattern *aFontName)
00124       : nsFontXft(aPattern, aFontName)
00125     { }
00126 
00127     virtual ~nsFontXftUnicode();
00128 
00129     virtual PRBool     HasChar (PRUint32 aChar);
00130 };
00131 
00132 // class for custom encoded fonts that pretend to have Unicode cmap.
00133 // There are two kinds of them: 
00134 // 1. 'narrow' custom encoded fonts such as  mathematica fonts, 
00135 // TeX Computer Roman fonts, Symbol font, etc.
00136 // 2. 'wide' custom  encoded fonts such as 
00137 // Korean Jamo fonts, non-opentype fonts for Indic scripts.
00138 //
00139 // The biggest difference between 'narrow' and 'wide' fonts is that 
00140 // the result of calling mConverter for 'wide' fonts is a sequence of 
00141 // 16bit pseudo-Unicode code points.  For 'narrow' fonts, it's 
00142 // a sequence of 8bit code points. 
00143 class nsFontXftCustom : public nsFontXft {
00144 public:
00145     nsFontXftCustom(FcPattern* aPattern, 
00146                     FcPattern* aFontName, 
00147                     nsFontXftInfo* aFontInfo)
00148       : nsFontXft(aPattern, aFontName)
00149       , mFontInfo(aFontInfo)
00150       , mFT_Face(nsnull)
00151     { }
00152 
00153     virtual ~nsFontXftCustom();
00154 
00155     virtual PRBool   HasChar            (PRUint32 aChar);
00156     virtual FT_UInt  CharToGlyphIndex   (FcChar32 aChar);
00157     virtual nsresult GetTextExtents32   (const FcChar32 *aString, 
00158                                          PRUint32 aLen, XGlyphInfo &aGlyphInfo);
00159     virtual nsresult DrawStringSpec     (FcChar32* aString, PRUint32 aLen,
00160                                          void *aData);
00161 
00162 private:
00163     nsFontXftInfo *mFontInfo; 
00164 
00165     // freetype fontface : used for direct access to glyph indices
00166     // in GetWidth32() and DrawStringSpec().
00167     FT_Face    mFT_Face;
00168     nsresult   SetFT_FaceCharmap (void);
00169 };
00170 
00171 enum nsXftFontType {
00172     eFontTypeUnicode,
00173     eFontTypeCustom,
00174     eFontTypeCustomWide
00175 };
00176 
00177 // a class to hold some essential information about font. 
00178 // it's shared and cached with 'family name' as hash key.
00179 class nsFontXftInfo {
00180     public:
00181     nsFontXftInfo() : mCCMap(nsnull), mConverter(0), 
00182                       mFontType(eFontTypeUnicode) 
00183                       { }
00184 
00185     ~nsFontXftInfo() {
00186         if (mCCMap)
00187             FreeCCMap(mCCMap);
00188     }
00189 
00190     // Char. coverage map(replacing mCharset in nsFontXft)
00191     PRUint16*                   mCCMap;
00192     // converter from Unicode to font-specific encoding
00193     nsCOMPtr<nsIUnicodeEncoder> mConverter;
00194     // Unicode, Custom, CustomWide
00195     nsXftFontType               mFontType;
00196     // Truetype cmap to use for direct retrieval of GIDs with FT_Get_Char_Index
00197     // for 'narrow' custom fonts.
00198     FT_Encoding                 mFT_Encoding;
00199 };
00200 
00201 struct DrawStringData {
00202     nscoord                x;
00203     nscoord                y;
00204     const nscoord         *spacing;
00205     nscoord                xOffset;
00206     nsCairoRenderingContext *context;
00207     XftDraw               *draw;
00208     XftColor               color;
00209     float                  p2t;
00210     nsAutoDrawSpecBuffer  *drawBuffer;
00211 };
00212 
00213 #ifdef MOZ_MATHML
00214 struct BoundingMetricsData {
00215     nsBoundingMetrics *bm;
00216     PRBool firstTime;
00217 };
00218 #endif /* MOZ_MATHML */
00219 
00220 #define AUTO_BUFFER_SIZE 3000
00221 typedef nsAutoBuffer<FcChar32, AUTO_BUFFER_SIZE> nsAutoFcChar32Buffer;
00222 
00223 static int      CompareFontNames (const void* aArg1, const void* aArg2,
00224                                   void* aClosure);
00225 static nsresult EnumFontsXft     (nsIAtom* aLangGroup, const char* aGeneric,
00226                                   PRUint32* aCount, PRUnichar*** aResult);
00227 
00228 static        void ConvertCharToUCS4    (const char *aString,
00229                                          PRUint32 aLength,
00230                                          nsAutoFcChar32Buffer &aOutBuffer,
00231                                          PRUint32 *aOutLen);
00232 static        void ConvertUnicharToUCS4 (const PRUnichar *aString,
00233                                          PRUint32 aLength,
00234                                          nsAutoFcChar32Buffer &aOutBuffer,
00235                                          PRUint32 *aOutLen);
00236 static    nsresult ConvertUCS4ToCustom  (FcChar32 *aSrc, PRUint32 aSrcLen,
00237                                          PRUint32& aDestLen, 
00238                                          nsIUnicodeEncoder *aConverter, 
00239                                          PRBool aIsWide, 
00240                                          nsAutoFcChar32Buffer &Result);
00241 
00242 #ifdef MOZ_WIDGET_GTK2
00243 static void GdkRegionSetXftClip(GdkRegion *aGdkRegion, XftDraw *aDraw);
00244 #endif
00245 
00246 // This is the scaling factor that we keep fonts limited to against
00247 // the display size.  If a pixel size is requested that is more than
00248 // this factor larger than the height of the display, it's clamped to
00249 // that value instead of the requested size.
00250 #define FONT_MAX_FONT_SCALE 2
00251 
00252 #define UCS2_REPLACEMENT 0xFFFD
00253 
00254 #define IS_NON_BMP(c) ((c) >> 16)
00255 #define IS_NON_SURROGATE(c) ((c < 0xd800 || c > 0xdfff))
00256 
00257 // a helper class for Xft glyph drawings
00258 class nsAutoDrawSpecBuffer {
00259 public:
00260     enum {BUFFER_LEN=1024};
00261     nsAutoDrawSpecBuffer(XftDraw *aDraw, XftColor *aColor) :
00262                          mDraw(aDraw), mColor(aColor), mSpecPos(0) {}
00263 
00264     ~nsAutoDrawSpecBuffer() {
00265         Flush();
00266     }
00267 
00268     void Flush();
00269     void Draw(nscoord x, nscoord y, XftFont *font, FT_UInt glyph);
00270 
00271 private:
00272     XftDraw         *mDraw;
00273     XftColor        *mColor;
00274     PRUint32         mSpecPos;
00275     XftGlyphFontSpec mSpecBuffer[BUFFER_LEN];
00276 };
00277 
00278 
00279 PRLogModuleInfo *gXftFontLoad = nsnull;
00280 static int gNumInstances = 0;
00281 
00282 #undef DEBUG_XFT_MEMORY
00283 #ifdef DEBUG_XFT_MEMORY
00284 
00285 extern "C" {
00286 extern void XftMemReport(void);
00287 extern void FcMemReport(void);
00288 }
00289 #endif
00290 
00291 static nsresult
00292 EnumFontsXft(nsIAtom* aLangGroup, const char* aGeneric,
00293              PRUint32* aCount, PRUnichar*** aResult);
00294  
00295 static NS_DEFINE_CID(kCharsetConverterManagerCID,
00296                      NS_ICHARSETCONVERTERMANAGER_CID);
00297 
00298 static PRBool                      gInitialized = PR_FALSE;
00299 static nsIPersistentProperties*    gFontEncodingProperties = nsnull;
00300 static nsICharsetConverterManager* gCharsetManager = nsnull;
00301 
00302 typedef nsClassHashtable<nsCharPtrHashKey, nsFontXftInfo> nsFontXftInfoHash; 
00303 static nsFontXftInfoHash           gFontXftMaps;
00304 #define INITIAL_FONT_MAP_SIZE      32
00305 
00306 static nsresult       GetEncoding(const char* aFontName,
00307                                   char **aEncoding,
00308                                   nsXftFontType &aType,
00309                                   FT_Encoding &aFTEncoding);
00310 static nsresult       GetConverter(const char* aEncoding,
00311                                    nsIUnicodeEncoder** aConverter);
00312 static nsresult       FreeGlobals(void);
00313 static nsFontXftInfo* GetFontXftInfo(FcPattern* aPattern);
00314 
00315 nsFontMetricsXft::nsFontMetricsXft(): mMiniFont(nsnull)
00316 {
00317     if (!gXftFontLoad)
00318         gXftFontLoad = PR_NewLogModule("XftFontLoad");
00319 
00320     ++gNumInstances;
00321 }
00322 
00323 nsFontMetricsXft::~nsFontMetricsXft()
00324 {
00325     if (mDeviceContext)
00326         mDeviceContext->FontMetricsDeleted(this);
00327 
00328     if (mPattern)
00329         FcPatternDestroy(mPattern);
00330 
00331     for (PRInt32 i= mLoadedFonts.Count() - 1; i >= 0; --i) {
00332         nsFontXft *font = (nsFontXft *)mLoadedFonts.ElementAt(i);
00333         delete font;
00334     }
00335 
00336     if (mMiniFont)
00337         XftFontClose(GDK_DISPLAY(), mMiniFont);
00338 
00339     if (--gNumInstances == 0) {
00340         FreeGlobals();
00341 #ifdef DEBUG_XFT_MEMORY
00342         XftMemReport();
00343         FcMemReport();
00344 #endif
00345     }
00346 }
00347 
00348 NS_IMPL_ISUPPORTS1(nsFontMetricsXft, nsIFontMetrics)
00349 
00350 // nsIFontMetrics impl
00351 
00352 NS_IMETHODIMP
00353 nsFontMetricsXft::Init(const nsFont& aFont, nsIAtom* aLangGroup,
00354                        nsIDeviceContext *aContext)
00355 {
00356     mFont = aFont;
00357     mLangGroup = aLangGroup;
00358 
00359     // Hang onto the device context
00360     mDeviceContext = aContext;
00361 
00362     float app2dev = mDeviceContext->AppUnitsToDevUnits();
00363     mPixelSize = NSTwipsToFloatPixels(mFont.size, app2dev);
00364 
00365     // Make sure to clamp the pixel size to something reasonable so we
00366     // don't make the X server blow up.
00367     nscoord screenPixels = 1200;//XXX pavlov gdk_screen_height();
00368     mPixelSize = PR_MIN(screenPixels * FONT_MAX_FONT_SCALE, mPixelSize);
00369 
00370     // enumerate over the font names passed in
00371     mFont.EnumerateFamilies(nsFontMetricsXft::EnumFontCallback, this);
00372 
00373     nsCOMPtr<nsIPref> prefService;
00374     prefService = do_GetService(NS_PREF_CONTRACTID);
00375     if (!prefService)
00376         return NS_ERROR_FAILURE;
00377         
00378     nsXPIDLCString value;
00379     const char* langGroup;
00380     mLangGroup->GetUTF8String(&langGroup);
00381 
00382     // Set up the default font name if it's not set
00383     if (!mGenericFont) {
00384         nsCAutoString name("font.default.");
00385         name.Append(langGroup);
00386         prefService->CopyCharPref(name.get(), getter_Copies(value));
00387 
00388         if (value.get())
00389             mDefaultFont = value.get();
00390         else
00391             mDefaultFont = "serif";
00392         
00393         mGenericFont = &mDefaultFont;
00394     }
00395 
00396     // set up the minimum sizes for fonts
00397     if (mLangGroup) {
00398         nsCAutoString name("font.min-size.");
00399 
00400         if (mGenericFont->Equals("monospace"))
00401             name.Append("fixed");
00402         else
00403             name.Append("variable");
00404 
00405         name.Append(char('.'));
00406         name.Append(langGroup);
00407 
00408         PRInt32 minimum = 0;
00409         nsresult res;
00410         res = prefService->GetIntPref(name.get(), &minimum);
00411         if (NS_FAILED(res))
00412             prefService->GetDefaultIntPref(name.get(), &minimum);
00413 
00414         if (minimum < 0)
00415             minimum = 0;
00416 
00417         if (mPixelSize < minimum)
00418             mPixelSize = minimum;
00419     }
00420 
00421     // Make sure that the pixel size is at least greater than zero
00422     if (mPixelSize < 1) {
00423 #ifdef DEBUG
00424         printf("*** Warning: nsFontMetricsXft was passed a pixel size of %f\n",
00425                mPixelSize);
00426 #endif
00427         mPixelSize = 1;
00428     }
00429     if (!gInitialized) {
00430         CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
00431         if (!gCharsetManager) {
00432             FreeGlobals();
00433             return NS_ERROR_FAILURE;
00434         }
00435 
00436         if (!gFontXftMaps.IsInitialized() && 
00437             !gFontXftMaps.Init(INITIAL_FONT_MAP_SIZE)) {
00438             FreeGlobals();
00439             return NS_ERROR_OUT_OF_MEMORY;
00440         }
00441 
00442         gInitialized = PR_TRUE;
00443     }
00444 
00445     if (NS_FAILED(RealizeFont()))
00446         return NS_ERROR_FAILURE;
00447 
00448     return NS_OK;
00449 }
00450 
00451 NS_IMETHODIMP
00452 nsFontMetricsXft::Destroy()
00453 {
00454     mDeviceContext = nsnull;
00455 
00456     return NS_OK;
00457 }
00458 
00459 NS_IMETHODIMP
00460 nsFontMetricsXft::GetLangGroup(nsIAtom** aLangGroup)
00461 {
00462     *aLangGroup = mLangGroup;
00463     NS_IF_ADDREF(*aLangGroup);
00464 
00465     return NS_OK;
00466 }
00467 
00468 NS_IMETHODIMP
00469 nsFontMetricsXft::GetFontHandle(nsFontHandle &aHandle)
00470 {
00471     return NS_ERROR_NOT_IMPLEMENTED;
00472 }
00473 
00474 // nsIFontMetricsXft impl
00475 
00476 nsresult
00477 nsFontMetricsXft::GetWidth(const char* aString, PRUint32 aLength,
00478                            nscoord& aWidth)
00479 {
00480     NS_TIMELINE_MARK_FUNCTION("GetWidth");
00481 
00482     XftFont *font = mWesternFont->mXftFont;
00483     NS_ASSERTION(font, "FindFont returned a bad font");
00484 
00485     XGlyphInfo glyphInfo;
00486 
00487     // casting away const for aString but it  should be safe
00488     XftTextExtents8(GDK_DISPLAY(), font, (FcChar8 *)aString,
00489                     aLength, &glyphInfo);
00490 
00491     float f;
00492     f = mDeviceContext->DevUnitsToAppUnits();
00493     aWidth = NSToCoordRound(glyphInfo.xOff * f);
00494 
00495     return NS_OK;
00496 }
00497 
00498 nsresult
00499 nsFontMetricsXft::GetWidth(const PRUnichar* aString, PRUint32 aLength,
00500                            nscoord& aWidth, PRInt32 *aFontID)
00501 {
00502     NS_TIMELINE_MARK_FUNCTION("GetWidth");
00503     if (!aLength) {
00504         aWidth = 0;
00505         return NS_OK;
00506     }
00507 
00508     gint rawWidth = RawGetWidth(aString, aLength);
00509 
00510     float f;
00511     f = mDeviceContext->DevUnitsToAppUnits();
00512     aWidth = NSToCoordRound(rawWidth * f);
00513 
00514     if (aFontID)
00515         *aFontID = 0;
00516 
00517     return NS_OK;
00518 }
00519 
00520 nsresult
00521 nsFontMetricsXft::GetTextDimensions(const PRUnichar* aString,
00522                                     PRUint32 aLength,
00523                                     nsTextDimensions& aDimensions, 
00524                                     PRInt32* aFontID)
00525 {
00526     NS_TIMELINE_MARK_FUNCTION("GetTextDimensions");
00527     aDimensions.Clear();
00528 
00529     if (!aLength)
00530         return NS_OK;
00531 
00532     nsresult rv;
00533     rv = EnumerateGlyphs(aString, aLength,
00534                          &nsFontMetricsXft::TextDimensionsCallback,
00535                          &aDimensions);
00536 
00537     NS_ENSURE_SUCCESS(rv, rv);
00538 
00539     float P2T;
00540     P2T = mDeviceContext->DevUnitsToAppUnits();
00541 
00542     aDimensions.width = NSToCoordRound(aDimensions.width * P2T);
00543     aDimensions.ascent = NSToCoordRound(aDimensions.ascent * P2T);
00544     aDimensions.descent = NSToCoordRound(aDimensions.descent * P2T);
00545 
00546     if (nsnull != aFontID)
00547         *aFontID = 0;
00548 
00549     return NS_OK;
00550 }
00551 
00552 nsresult
00553 nsFontMetricsXft::GetTextDimensions(const char*         aString,
00554                                     PRInt32             aLength,
00555                                     PRInt32             aAvailWidth,
00556                                     PRInt32*            aBreaks,
00557                                     PRInt32             aNumBreaks,
00558                                     nsTextDimensions&   aDimensions,
00559                                     PRInt32&            aNumCharsFit,
00560                                     nsTextDimensions&   aLastWordDimensions,
00561                                     PRInt32*            aFontID)
00562 {
00563     NS_NOTREACHED("GetTextDimensions");
00564     return NS_ERROR_NOT_IMPLEMENTED;
00565 }
00566 
00567 nsresult
00568 nsFontMetricsXft::GetTextDimensions(const PRUnichar*    aString,
00569                                     PRInt32             aLength,
00570                                     PRInt32             aAvailWidth,
00571                                     PRInt32*            aBreaks,
00572                                     PRInt32             aNumBreaks,
00573                                     nsTextDimensions&   aDimensions,
00574                                     PRInt32&            aNumCharsFit,
00575                                     nsTextDimensions&   aLastWordDimensions,
00576                                     PRInt32*            aFontID)
00577 {
00578     NS_NOTREACHED("GetTextDimensions");
00579     return NS_ERROR_NOT_IMPLEMENTED;
00580 }
00581 
00582 nsresult
00583 nsFontMetricsXft::DrawString(const char *aString, PRUint32 aLength,
00584                              nscoord aX, nscoord aY,
00585                              const nscoord* aSpacing,
00586                              nsCairoRenderingContext *aContext,
00587                              nsCairoDrawingSurface *aSurface)
00588 {
00589     NS_TIMELINE_MARK_FUNCTION("DrawString");
00590 
00591     // The data we will carry through the function
00592     DrawStringData data;
00593     memset(&data, 0, sizeof(data));
00594 
00595     data.x = aX;
00596     data.y = aY;
00597     data.spacing = aSpacing;
00598     data.context = aContext;
00599     data.p2t = mDeviceContext->DevUnitsToAppUnits();
00600 
00601     PrepareToDraw(aContext, aSurface, &data.draw, data.color);
00602 
00603     nsAutoDrawSpecBuffer drawBuffer(data.draw, &data.color);
00604     data.drawBuffer = &drawBuffer;
00605 
00606     return EnumerateGlyphs(aString, aLength,
00607                            &nsFontMetricsXft::DrawStringCallback, &data);
00608 }
00609 
00610 nsresult
00611 nsFontMetricsXft::DrawString(const PRUnichar* aString, PRUint32 aLength,
00612                              nscoord aX, nscoord aY,
00613                              PRInt32 aFontID,
00614                              const nscoord* aSpacing,
00615                              nsCairoRenderingContext *aContext,
00616                              nsCairoDrawingSurface *aSurface)
00617 {
00618     NS_TIMELINE_MARK_FUNCTION("DrawString");
00619 
00620     // The data we will carry through the function
00621     DrawStringData data;
00622     memset(&data, 0, sizeof(data));
00623 
00624     data.x = aX;
00625     data.y = aY;
00626     data.spacing = aSpacing;
00627     data.context = aContext;
00628     data.p2t = mDeviceContext->DevUnitsToAppUnits();
00629 
00630     // set up our colors and clip regions
00631     PrepareToDraw(aContext, aSurface, &data.draw, data.color);
00632 
00633     nsAutoDrawSpecBuffer drawBuffer(data.draw, &data.color);
00634     data.drawBuffer = &drawBuffer;
00635 
00636     return EnumerateGlyphs(aString, aLength,
00637                            &nsFontMetricsXft::DrawStringCallback, &data);
00638 }
00639 
00640 #ifdef MOZ_MATHML
00641 
00642 nsresult
00643 nsFontMetricsXft::GetBoundingMetrics(const char *aString, PRUint32 aLength,
00644                                      nsBoundingMetrics &aBoundingMetrics,
00645                                      nsCairoRenderingContext *aContext)
00646 {
00647     aBoundingMetrics.Clear(); 
00648 
00649     if (!aString || !aLength)
00650         return NS_ERROR_FAILURE;
00651 
00652     // The data we will carry through the function
00653     BoundingMetricsData data;
00654     data.bm = &aBoundingMetrics;
00655     // the beginning of a string needs a special treatment (see
00656     // 'operator +' definition of nsBoundingMetrics.)
00657     data.firstTime = PR_TRUE; 
00658 
00659     nsresult rv;
00660     rv = EnumerateGlyphs(aString, aLength,
00661                          &nsFontMetricsXft::BoundingMetricsCallback, &data);
00662     NS_ENSURE_SUCCESS(rv, rv);
00663 
00664     float P2T;
00665     P2T = mDeviceContext->DevUnitsToAppUnits();
00666 
00667     aBoundingMetrics.leftBearing =
00668         NSToCoordRound(aBoundingMetrics.leftBearing * P2T);
00669     aBoundingMetrics.rightBearing =
00670         NSToCoordRound(aBoundingMetrics.rightBearing * P2T);
00671     aBoundingMetrics.width = NSToCoordRound(aBoundingMetrics.width * P2T);
00672     aBoundingMetrics.ascent = NSToCoordRound(aBoundingMetrics.ascent * P2T);
00673     aBoundingMetrics.descent = NSToCoordRound(aBoundingMetrics.descent * P2T);
00674 
00675     return NS_OK;
00676 }
00677 
00678 nsresult
00679 nsFontMetricsXft::GetBoundingMetrics(const PRUnichar *aString,
00680                                      PRUint32 aLength,
00681                                      nsBoundingMetrics &aBoundingMetrics,
00682                                      PRInt32 *aFontID,
00683                                      nsCairoRenderingContext *aContext)
00684 {
00685     aBoundingMetrics.Clear(); 
00686 
00687     if (!aString || !aLength)
00688         return NS_ERROR_FAILURE;
00689 
00690     // The data we will carry through the function
00691     BoundingMetricsData data;
00692     data.bm = &aBoundingMetrics;
00693     // the beginning of a string needs a special treatment (see
00694     // 'operator +' definition of nsBoundingMetrics.)
00695     data.firstTime = PR_TRUE; 
00696 
00697     nsresult rv;
00698     rv = EnumerateGlyphs(aString, aLength,
00699                          &nsFontMetricsXft::BoundingMetricsCallback, &data);
00700     NS_ENSURE_SUCCESS(rv, rv);
00701 
00702     float P2T;
00703     P2T = mDeviceContext->DevUnitsToAppUnits();
00704 
00705     aBoundingMetrics.leftBearing =
00706         NSToCoordRound(aBoundingMetrics.leftBearing * P2T);
00707     aBoundingMetrics.rightBearing =
00708         NSToCoordRound(aBoundingMetrics.rightBearing * P2T);
00709     aBoundingMetrics.width = NSToCoordRound(aBoundingMetrics.width * P2T);
00710     aBoundingMetrics.ascent = NSToCoordRound(aBoundingMetrics.ascent * P2T);
00711     aBoundingMetrics.descent = NSToCoordRound(aBoundingMetrics.descent * P2T);
00712 
00713     if (nsnull != aFontID)
00714         *aFontID = 0;
00715 
00716     return NS_OK;
00717 }
00718 
00719 #endif /* MOZ_MATHML */
00720 
00721 nsresult
00722 nsFontMetricsXft::SetRightToLeftText(PRBool aIsRTL)
00723 {
00724     return NS_OK;
00725 }
00726 
00727 PRUint32
00728 nsFontMetricsXft::GetHints(void)
00729 {
00730     return 0;
00731 }
00732 
00733 nsresult
00734 nsFontMetricsXft::RealizeFont(void)
00735 {
00736     // make sure that the western font is loaded since we need that to
00737     // get the font metrics
00738     mWesternFont = FindFont('a');
00739     if (!mWesternFont)
00740         return NS_ERROR_FAILURE;
00741 
00742     return CacheFontMetrics();
00743 }
00744 
00745 // rounding and truncation functions for a Freetype floating point number 
00746 // (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
00747 // part and low 6 bits for the fractional part. 
00748 #define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1
00749 #define MOZ_FT_TRUNC(x) ((x) >> 6)
00750 #define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
00751         MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
00752 
00753 nsresult
00754 nsFontMetricsXft::CacheFontMetrics(void)
00755 {
00756     // Get our scale factor
00757     float f;
00758     float val;
00759     f = mDeviceContext->DevUnitsToAppUnits();
00760     
00761     // Get our font face
00762     FT_Face face;
00763     TT_OS2 *os2;
00764     XftFont *xftFont = mWesternFont->mXftFont;
00765     NS_ASSERTION(xftFont, "FindFont returned a bad font");
00766 
00767     face = XftLockFace(xftFont);
00768     os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
00769 
00770     // mEmHeight (size in pixels of EM height)
00771     int size;
00772     if (FcPatternGetInteger(mWesternFont->mPattern, FC_PIXEL_SIZE, 0, &size) !=
00773         FcResultMatch) {
00774         size = 12;
00775     }
00776     mEmHeight = PR_MAX(1, nscoord(size * f));
00777 
00778     // mMaxAscent
00779     mMaxAscent = nscoord(xftFont->ascent * f);
00780 
00781     // mMaxDescent
00782     mMaxDescent = nscoord(xftFont->descent * f);
00783 
00784     nscoord lineHeight = mMaxAscent + mMaxDescent;
00785 
00786     // mLeading (needs ascent and descent and EM height) 
00787     if (lineHeight > mEmHeight)
00788         mLeading = lineHeight - mEmHeight;
00789     else
00790         mLeading = 0;
00791 
00792     // mMaxHeight (needs ascent and descent)
00793     mMaxHeight = lineHeight;
00794 
00795     // mEmAscent (needs maxascent, EM height, ascent and descent)
00796     mEmAscent = nscoord(mMaxAscent * mEmHeight / lineHeight);
00797 
00798     // mEmDescent (needs EM height and EM ascent
00799     mEmDescent = mEmHeight - mEmAscent;
00800 
00801     // mMaxAdvance
00802     mMaxAdvance = nscoord(xftFont->max_advance_width * f);
00803 
00804     // mSpaceWidth (width of a space)
00805     gint rawWidth;
00806     PRUnichar unispace(' ');
00807     rawWidth = RawGetWidth(&unispace, 1);
00808     mSpaceWidth = NSToCoordRound(rawWidth * f);
00809 
00810     // mAveCharWidth (width of an 'average' char)
00811     PRUnichar xUnichar('x');
00812     rawWidth = RawGetWidth(&xUnichar, 1);
00813     mAveCharWidth = NSToCoordRound(rawWidth * f);
00814 
00815     // mXHeight (height of an 'x' character)
00816     if (FcCharSetHasChar(mWesternFont->mCharset, xUnichar)) {
00817         XGlyphInfo extents;
00818         XftTextExtents16(GDK_DISPLAY(), xftFont, &xUnichar, 1, &extents);
00819         mXHeight = extents.height;
00820     }
00821     else {
00822         // 56% of ascent, best guess for non-true type or asian fonts
00823         mXHeight = nscoord(((float)mMaxAscent) * 0.56);
00824     }
00825     mXHeight = nscoord(mXHeight * f);
00826 
00827     // mUnderlineOffset (offset for underlines)
00828     val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_position,
00829                                          face->size->metrics.y_scale);
00830     if (val) {
00831         mUnderlineOffset = NSToIntRound(val * f);
00832     }
00833     else {
00834         mUnderlineOffset =
00835             -NSToIntRound(PR_MAX(1, floor(0.1 * xftFont->height + 0.5)) * f);
00836     }
00837 
00838     // mUnderlineSize (thickness of an underline)
00839     val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness,
00840                                          face->size->metrics.y_scale);
00841     if (val) {
00842         mUnderlineSize = nscoord(PR_MAX(f, NSToIntRound(val * f)));
00843     }
00844     else {
00845         mUnderlineSize =
00846             NSToIntRound(PR_MAX(1, floor(0.05 * xftFont->height + 0.5)) * f);
00847     }
00848 
00849     // mSuperscriptOffset
00850     if (os2 && os2->ySuperscriptYOffset) {
00851         val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySuperscriptYOffset,
00852                                              face->size->metrics.y_scale);
00853         mSuperscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f)));
00854     }
00855     else {
00856         mSuperscriptOffset = mXHeight;
00857     }
00858 
00859     // mSubscriptOffset
00860     if (os2 && os2->ySubscriptYOffset) {
00861         val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySubscriptYOffset,
00862                                              face->size->metrics.y_scale);
00863         // some fonts have the incorrect sign. 
00864         val = (val < 0) ? -val : val;
00865         mSubscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f)));
00866     }
00867     else {
00868         mSubscriptOffset = mXHeight;
00869     }
00870 
00871     // mStrikeoutOffset
00872     mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0);
00873 
00874     // mStrikeoutSize
00875     mStrikeoutSize = mUnderlineSize;
00876 
00877     XftUnlockFace(xftFont);
00878 
00879     return NS_OK;
00880 }
00881 
00882 nsFontXft *
00883 nsFontMetricsXft::FindFont(PRUint32 aChar)
00884 {
00885 
00886     // If mPattern is null, set up the base bits of it so we can
00887     // match.  If we need to match later we don't have to set it up
00888     // again.
00889     if (!mPattern) {
00890         SetupFCPattern();
00891         // did we fail to set it up?
00892         if (!mPattern)
00893             return nsnull;
00894     }
00895 
00896     // go forth and find us some fonts
00897     if (mMatchType == eNoMatch) {
00898         // Optimistically just look for the best match font.
00899         // This can be completed in linear time, which is ideal if all
00900         // of the characters we're asked for can be found in this font.
00901         DoMatch(PR_FALSE);
00902     }
00903 
00904     // Now that we have the fonts loaded and ready to run, return the
00905     // font in our loaded list that supports the character
00906 
00907     if (mLoadedFonts.Count() == 0) {
00908         // No fonts were matched at all.  This probably means out-of-memory
00909         // or some equally bad condition.
00910         return nsnull;
00911     }
00912 
00913     PRBool removeFirstFont = PR_FALSE;
00914     nsFontXft *font = (nsFontXft *)mLoadedFonts.ElementAt(0);
00915     if (font->HasChar(aChar)) {
00916         if (font->GetXftFont())
00917             return font;
00918         removeFirstFont = PR_TRUE;
00919     }
00920 
00921     // We failed to find the character in the best-match font, so load
00922     // _all_ matching fonts if we haven't already done so.
00923 
00924     if (mMatchType == eBestMatch)
00925         DoMatch(PR_TRUE);
00926 
00927     PRInt32 i = 1;
00928     if (removeFirstFont) {
00929         // The first font was bad, so remove it (see below).  But do this
00930         // after |DoMatch| since otherwise it will get re-added.
00931         mLoadedFonts.RemoveElementAt(0);
00932         i = 0;
00933     }
00934 
00935     // Now check the remaining fonts
00936     for (; i < mLoadedFonts.Count(); ++i) {
00937         nsFontXft *font = (nsFontXft *)mLoadedFonts.ElementAt(i);
00938         if (font->HasChar(aChar)) {
00939             if (font->GetXftFont())
00940                 return font;
00941             // This is a bad font, so remove it from mLoadedFonts.  This
00942             // could happen if it's in fc.cache-1 but the font doesn't exist
00943             // (https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=111973)
00944             // or isn't readable.
00945             mLoadedFonts.RemoveElementAt(i--);
00946         }
00947     }
00948 
00949     // If we got this far, none of the fonts support this character.
00950     // Return nothing.
00951     return nsnull;
00952 }
00953 
00954 void
00955 nsFontMetricsXft::SetupFCPattern(void)
00956 {
00957     if (PR_LOG_TEST(gXftFontLoad, PR_LOG_DEBUG)) {
00958         printf("[%p] setting up pattern with the following specification:\n",
00959                (void *)this);
00960 
00961         // non-generic families
00962         if (mFontList.Count() && !mFontIsGeneric[0]) {
00963             printf("\tadding non-generic families: ");
00964             for (int i=0; i < mFontList.Count(); ++i) {
00965                 if (mFontIsGeneric[i])
00966                     break;
00967 
00968                 nsCString *familyName = mFontList.CStringAt(i);
00969                 printf("%s, ", familyName->get());
00970             }
00971             printf("\n");
00972         }
00973 
00974         // language group
00975         const char *name;
00976         mLangGroup->GetUTF8String(&name);
00977         printf("\tlang group: %s\n", name);
00978 
00979 
00980     }
00981 
00982     mPattern = FcPatternCreate();
00983     if (!mPattern)
00984         return;
00985 
00986     if (gdk_rgb_get_cmap() != gdk_colormap_get_system())
00987         XftPatternAddBool(mPattern, XFT_RENDER, False);
00988 
00989     // XXX need to add user defined family
00990 
00991     // Add CSS names - walk the list of fonts, adding the generic as
00992     // the last font
00993     for (int i=0; i < mFontList.Count(); ++i) {
00994         // if this was a generic name, break out of the loop since we
00995         // don't want to add it to the pattern yet
00996         if (mFontIsGeneric[i])
00997             break;;
00998 
00999         nsCString *familyName = mFontList.CStringAt(i);
01000         NS_AddFFRE(mPattern, familyName, PR_FALSE);
01001     }
01002 
01003     // Add the language group.  Note that we do this before adding any
01004     // generics.  That's because the language is more important than
01005     // any generic font.
01006     NS_AddLangGroup (mPattern, mLangGroup);
01007 
01008     // If there's a generic add a pref for the generic if there's one
01009     // set.
01010     if (mGenericFont && !mFont.systemFont) {
01011         NS_AddGenericFontFromPref(mGenericFont, mLangGroup, mPattern,
01012                                   gXftFontLoad);
01013     }
01014 
01015     // Add the generic if there is one.
01016     if (mGenericFont && !mFont.systemFont)
01017         NS_AddFFRE(mPattern, mGenericFont, PR_FALSE);
01018 
01019     if (PR_LOG_TEST(gXftFontLoad, PR_LOG_DEBUG)) {
01020         // generic font
01021         if (mGenericFont && !mFont.systemFont) {
01022             printf("\tadding generic family: %s\n", mGenericFont->get());
01023         }
01024 
01025         // pixel size
01026         printf("\tpixel,twip size: %f,%d\n", mPixelSize, mFont.size);
01027 
01028         // slant type
01029         printf("\tslant: ");
01030         switch(mFont.style) {
01031         case NS_FONT_STYLE_ITALIC:
01032             printf("italic\n");
01033             break;
01034         case NS_FONT_STYLE_OBLIQUE:
01035             printf("oblique\n");
01036             break;
01037         default:
01038             printf("roman\n");
01039             break;
01040         }
01041 
01042         // weight
01043         printf("\tweight: (orig,calc) %d,%d\n",
01044                mFont.weight, NS_CalculateWeight(mFont.weight));
01045 
01046     }        
01047 
01048     // add the point size
01049     // We've done some round-tripping of floating point numbers so they
01050     // might not be quite right.  Since Xft rounds down, add a little,
01051     // so we don't go from 9.00000 to 8.99999 to 8.
01052     FcPatternAddDouble(mPattern, FC_PIXEL_SIZE, mPixelSize + 0.000001);
01053 
01054     // Add the slant type
01055     FcPatternAddInteger(mPattern, FC_SLANT,
01056                         NS_CalculateSlant(mFont.style));
01057 
01058     // Add the weight
01059     FcPatternAddInteger(mPattern, FC_WEIGHT,
01060                         NS_CalculateWeight(mFont.weight));
01061 
01062     // Set up the default substitutions for this font
01063     FcConfigSubstitute(0, mPattern, FcMatchPattern);
01064     XftDefaultSubstitute(GDK_DISPLAY(), DefaultScreen(GDK_DISPLAY()),
01065                          mPattern);
01066 }
01067 
01068 void
01069 nsFontMetricsXft::DoMatch(PRBool aMatchAll)
01070 {
01071     FcFontSet *set = nsnull;
01072     // now that we have a pattern we can match
01073     FcResult   result;
01074 
01075     if (aMatchAll) {
01076         set = FcFontSort(0, mPattern, FcTrue, NULL, &result);
01077         if (!set || set->nfont == 1) {
01078             // There is a bug in older fontconfig versions that causes it to
01079             // bail if it hits a font it can't deal with.
01080             // If this has happened, try just the generic font-family by
01081             // removing everything else from the font list and rebuilding
01082             // the pattern.
01083 
01084             NS_WARNING("Detected buggy fontconfig, falling back to generic font");
01085 
01086             nsCAutoString genericFont;
01087             if (mGenericFont)
01088                 genericFont.Assign(*mGenericFont);
01089 
01090             mFontList.Clear();
01091             mFontIsGeneric.Clear();
01092 
01093             mFontList.AppendCString(genericFont);
01094             mFontIsGeneric.AppendElement((void*) PR_TRUE);
01095             mGenericFont = mFontList.CStringAt(0);
01096 
01097             FcPatternDestroy(mPattern);
01098             SetupFCPattern();
01099 
01100             if (set)
01101                 FcFontSetDestroy(set);
01102 
01103             set = FcFontSort(0, mPattern, FcTrue, NULL, &result);
01104         }
01105     }
01106     else {
01107         FcPattern* font = FcFontMatch(0, mPattern, &result);
01108         if (font) {
01109             set = FcFontSetCreate();
01110             FcFontSetAdd(set, font);
01111         }
01112     }
01113 
01114     // did we not match anything?
01115     if (!set) {
01116         goto loser;
01117     }
01118 
01119     if (PR_LOG_TEST(gXftFontLoad, PR_LOG_DEBUG)) {
01120         printf("matched the following (%d) fonts:\n", set->nfont);
01121     }
01122 
01123     // Create a list of new font objects based on the fonts returned
01124     // as part of the query. We start at mLoadedFonts.Count() so as to
01125     // not re-add the best match font we've already loaded.
01126     for (int i=mLoadedFonts.Count(); i < set->nfont; ++i) {
01127         if (PR_LOG_TEST(gXftFontLoad, PR_LOG_DEBUG)) {
01128             char *name;
01129             FcPatternGetString(set->fonts[i], FC_FAMILY, 0, (FcChar8 **)&name);
01130             printf("\t%s\n", name);
01131         }
01132 
01133         nsFontXft *font;
01134         nsFontXftInfo *info;
01135         nsCOMPtr<nsIUnicodeEncoder> converter = 0;
01136 
01137         info = GetFontXftInfo(set->fonts[i]);
01138         if (info) {
01139             if (info->mFontType == eFontTypeUnicode)
01140                 font = new nsFontXftUnicode(mPattern, set->fonts[i]);
01141             else
01142                 font = new nsFontXftCustom(mPattern, set->fonts[i], info);
01143         }
01144         else {  // if null is returned, treat it as Unicode font.
01145             font = new nsFontXftUnicode(mPattern, set->fonts[i]);
01146         }
01147 
01148         if (!font)
01149             goto loser;
01150 
01151         // append this font to our list of loaded fonts
01152         mLoadedFonts.AppendElement((void *)font);
01153     }
01154 
01155     // we're done with the set now
01156     FcFontSetDestroy(set);
01157     set = nsnull;
01158 
01159     // Done matching!
01160     if (aMatchAll)
01161         mMatchType = eAllMatching;
01162     else
01163         mMatchType = eBestMatch;
01164     return;
01165 
01166     // if we got this far, something went terribly wrong
01167  loser:
01168     NS_WARNING("nsFontMetricsXft::DoMatch failed to match anything");
01169 
01170     if (set)
01171         FcFontSetDestroy(set);
01172 
01173     for (PRInt32 i = mLoadedFonts.Count() - 1; i >= 0; --i) {
01174         nsFontXft *font = (nsFontXft *)mLoadedFonts.ElementAt(i);
01175         mLoadedFonts.RemoveElementAt(i);
01176         delete font;
01177     }
01178 }
01179 
01180 gint
01181 nsFontMetricsXft::RawGetWidth(const PRUnichar* aString, PRUint32 aLength)
01182 {
01183     nscoord width = 0;
01184     nsresult rv;
01185 
01186     rv = EnumerateGlyphs(aString, aLength,
01187                          &nsFontMetricsXft::GetWidthCallback, &width);
01188 
01189     if (NS_FAILED(rv))
01190         width = 0;
01191 
01192     return width;
01193 }
01194 
01195 nsresult
01196 nsFontMetricsXft::SetupMiniFont(void)
01197 {
01198     // The minifont is initialized lazily.
01199     if (mMiniFont)
01200         return NS_OK;
01201 
01202     FcPattern *pattern = nsnull;
01203     XftFont *font = nsnull;
01204     XftFont *xftFont = mWesternFont->mXftFont;
01205     NS_ASSERTION(xftFont, "FindFont returned a bad font");
01206 
01207     mMiniFontAscent = xftFont->ascent;
01208     mMiniFontDescent = xftFont->descent;
01209 
01210     pattern = FcPatternCreate();
01211     if (!pattern)
01212         return NS_ERROR_FAILURE;
01213 
01214     if (gdk_rgb_get_cmap() != gdk_colormap_get_system())
01215         XftPatternAddBool(mPattern, XFT_RENDER, False);
01216 
01217     FcPatternAddString(pattern, FC_FAMILY, (FcChar8 *)"monospace");
01218 
01219     FcPatternAddInteger(pattern, FC_PIXEL_SIZE, int(0.5 * mPixelSize));
01220 
01221     FcPatternAddInteger(pattern, FC_WEIGHT,
01222                         NS_CalculateWeight(mFont.weight));
01223 
01224     FcConfigSubstitute(0, pattern, FcMatchPattern);
01225     XftDefaultSubstitute(GDK_DISPLAY(), DefaultScreen(GDK_DISPLAY()),
01226                          pattern);
01227 
01228     FcResult res;
01229     
01230     FcPattern *pat = FcFontMatch(0, pattern, &res);
01231 
01232     if (pat) {
01233         font = XftFontOpenPattern(GDK_DISPLAY(), pat);
01234 
01235         if (font) {
01236             mMiniFont = font;
01237             pat = nsnull; // the font owns the pattern now
01238         }
01239         else {
01240             font = xftFont;
01241         }
01242     }
01243 
01244     // now that the font has been loaded, measure the fonts to find
01245     // the bounds
01246     for (int i=0; i < 16; ++i) {
01247         // create a little mini-string that contains what we want to
01248         // measure.
01249         char c = i < 10 ? '0' + i : 'A' + i - 10;
01250         char str[2];
01251         str[0] = c;
01252         str[1] = '\0';
01253 
01254         XGlyphInfo extents;
01255         XftTextExtents8(GDK_DISPLAY(), font,
01256                         (FcChar8 *)str, 1, &extents);
01257 
01258         mMiniFontWidth = PR_MAX (mMiniFontWidth, extents.width);
01259         mMiniFontHeight = PR_MAX (mMiniFontHeight, extents.height);
01260     }
01261 
01262     if (!mMiniFont) {
01263         mMiniFontWidth /= 2;
01264         mMiniFontHeight /= 2;
01265     }
01266 
01267     mMiniFontPadding = PR_MAX(mMiniFontHeight / 10, 1);
01268     mMiniFontYOffset = ((mMiniFontAscent + mMiniFontDescent) -
01269                         (mMiniFontHeight * 2 + mMiniFontPadding * 5)) / 2;
01270 
01271 
01272     if (pat)
01273         FcPatternDestroy(pat);
01274     if (pattern)
01275         FcPatternDestroy(pattern);
01276 
01277     return NS_OK;
01278 }
01279 
01280 nsresult
01281 nsFontMetricsXft::DrawUnknownGlyph(FcChar32   aChar,
01282                                    nscoord    aX,
01283                                    nscoord    aY,
01284                                    XftColor  *aColor,
01285                                    XftDraw   *aDraw)
01286 {
01287     int width,height;
01288     int ndigit = (IS_NON_BMP(aChar)) ? 3 : 2;
01289 
01290     // ndigit characters + padding around the fonts.  From left to
01291     // right it would be one padding for the glyph box, one for the
01292     // padding in between the box and the left most digit, ndigit
01293     // padding following each of ndigit letters and one for the
01294     // rightmost part of the box.  This pattern is used throughout the
01295     // rest of this function.
01296     width = mMiniFontWidth * ndigit + mMiniFontPadding * (ndigit + 3);
01297     height = mMiniFontHeight * 2 + mMiniFontPadding * 5;
01298 
01299     // Draw an outline of a box.  We do with this with four calls
01300     // since with one call it would fill in the box.
01301     
01302     // horizontal lines
01303     XftDrawRect(aDraw, aColor,
01304                 aX, aY - height,
01305                 width, mMiniFontPadding);
01306     XftDrawRect(aDraw, aColor,
01307                 aX, aY - mMiniFontPadding,
01308                 width, mMiniFontPadding);
01309 
01310     // vertical lines
01311     XftDrawRect(aDraw, aColor,
01312                 aX,
01313                 aY - height + mMiniFontPadding,
01314                 mMiniFontPadding, height - mMiniFontPadding * 2);
01315     XftDrawRect(aDraw, aColor,
01316                 aX + width - mMiniFontPadding,
01317                 aY - height + mMiniFontPadding,
01318                 mMiniFontPadding, height - mMiniFontPadding * 2);
01319 
01320     // If for some reason the mini font couldn't be loaded, just
01321     // return - the box is enough.
01322     if (!mMiniFont)
01323         return NS_OK;
01324 
01325     // now draw the characters
01326     char buf[7];
01327     PR_snprintf (buf, sizeof(buf), "%0*X", ndigit * 2, aChar);
01328 
01329     // Draw the 'ndigit * 2' characters
01330     XftDrawString8(aDraw, aColor, mMiniFont,
01331                    aX + mMiniFontPadding * 2,
01332                    aY - mMiniFontHeight - mMiniFontPadding * 3,
01333                    (FcChar8 *)&buf[0], 1);
01334     XftDrawString8(aDraw, aColor, mMiniFont,
01335                    aX + mMiniFontWidth + mMiniFontPadding * 3,
01336                    aY - mMiniFontHeight - mMiniFontPadding * 3,
01337                    (FcChar8 *)&buf[1], 1);
01338 
01339     if (ndigit == 2) {
01340         XftDrawString8(aDraw, aColor, mMiniFont,
01341                        aX + mMiniFontPadding * 2,
01342                        aY - mMiniFontPadding * 2,
01343                        (FcChar8 *)&buf[2], 1);
01344         XftDrawString8(aDraw, aColor, mMiniFont,
01345                        aX + mMiniFontWidth + mMiniFontPadding * 3,
01346                        aY - mMiniFontPadding * 2,
01347                        (FcChar8 *)&buf[3], 1);
01348 
01349         return NS_OK;
01350     }
01351 
01352     XftDrawString8(aDraw, aColor, mMiniFont,
01353                    aX + mMiniFontWidth * 2 + mMiniFontPadding * 4,
01354                    aY - mMiniFontHeight - mMiniFontPadding * 3,
01355                    (FcChar8 *)&buf[2], 1);
01356     XftDrawString8(aDraw, aColor, mMiniFont,
01357                    aX + mMiniFontPadding * 2,
01358                    aY - mMiniFontPadding * 2,
01359                    (FcChar8 *)&buf[3], 1);
01360     XftDrawString8(aDraw, aColor, mMiniFont,
01361                    aX + mMiniFontWidth + mMiniFontPadding * 3,
01362                    aY - mMiniFontPadding * 2,
01363                    (FcChar8 *)&buf[4], 1);
01364     XftDrawString8(aDraw, aColor, mMiniFont,
01365                    aX + mMiniFontWidth * 2 + mMiniFontPadding * 4,
01366                    aY - mMiniFontPadding * 2,
01367                    (FcChar8 *)&buf[5], 1);
01368 
01369     return NS_OK;
01370 }
01371 
01372 nsresult
01373 nsFontMetricsXft::EnumerateXftGlyphs(const FcChar32 *aString, PRUint32 aLen,
01374                                      GlyphEnumeratorCallback aCallback,
01375                                      void *aCallbackData)
01376 {
01377     nsFontXft* prevFont = nsnull;
01378     PRUint32 start = 0;
01379     nsresult rv = NS_OK;
01380     PRUint32 i = 0;
01381 
01382     for ( ; i < aLen; i ++) {
01383         nsFontXft *currFont = FindFont(aString[i]);
01384 
01385         // Don't try to handle more than 512 characters at once, since
01386         // Xft text measurement can't deal with anything with a width of
01387         // more than 2^15 (32768) pixels.  This is a hack, and it could
01388         // break things like combining characters, but that's not nearly
01389         // as bad as not displaying anything, and it's also very rare to
01390         // draw strings this long without any breaks.
01391         if (currFont != prevFont || i - start > 512) {
01392             if (i > start) {
01393                 rv = (this->*aCallback)(&aString[start], i - start, prevFont,
01394                                         aCallbackData);
01395                 NS_ENSURE_SUCCESS(rv, rv);
01396             }
01397             prevFont = currFont;
01398             start = i;
01399         }
01400     }
01401 
01402     if (i > start)
01403         rv = (this->*aCallback)(&aString[start], i - start, prevFont,
01404                                 aCallbackData);
01405 
01406     return rv;
01407 }
01408 
01409 nsresult
01410 nsFontMetricsXft::EnumerateGlyphs(const PRUnichar *aString,
01411                                   PRUint32 aLen,
01412                                   GlyphEnumeratorCallback aCallback,
01413                                   void *aCallbackData)
01414 {
01415     PRUint32 len;
01416     nsAutoFcChar32Buffer charBuffer;
01417 
01418     NS_ENSURE_TRUE(aLen, NS_OK); 
01419 
01420     ConvertUnicharToUCS4(aString, aLen, charBuffer, &len);
01421     if (!len)
01422         return NS_ERROR_OUT_OF_MEMORY;
01423 
01424     return EnumerateXftGlyphs(charBuffer.get(), len, aCallback, aCallbackData);
01425 }
01426 
01427 nsresult
01428 nsFontMetricsXft::EnumerateGlyphs(const char *aString,
01429                                   PRUint32 aLen,
01430                                   GlyphEnumeratorCallback aCallback,
01431                                   void *aCallbackData)
01432 {
01433     PRUint32 len;
01434     nsAutoFcChar32Buffer charBuffer;
01435 
01436     NS_ENSURE_TRUE(aLen, NS_OK); 
01437 
01438     // Convert the incoming string into an array of UCS4 chars
01439     ConvertCharToUCS4(aString, aLen, charBuffer, &len);
01440     if (!len)
01441         return NS_ERROR_OUT_OF_MEMORY;
01442 
01443     return EnumerateXftGlyphs(charBuffer.get(), len, aCallback, aCallbackData);
01444 }
01445 
01446 void
01447 nsFontMetricsXft::PrepareToDraw(nsCairoRenderingContext *aContext,
01448                                 nsCairoDrawingSurface *aSurface,
01449                                 XftDraw **aDraw, XftColor &aColor)
01450 {
01451     // Set our color
01452     nscolor rccolor;
01453 
01454     aContext->GetColor(rccolor);
01455 #define NS_TO_GDK_RGB(ns) \
01456   ((ns & 0xff) << 16 | (ns & 0xff00) | ((ns >> 16) & 0xff))
01457 #define GDK_COLOR_TO_NS_RGB(c) \
01458   ((nscolor) NS_RGB(c.red, c.green, c.blue))
01459 
01460     aColor.pixel = gdk_rgb_xpixel_from_rgb(NS_TO_GDK_RGB(rccolor));
01461     aColor.color.red = (NS_GET_R(rccolor) << 8) | NS_GET_R(rccolor);
01462     aColor.color.green = (NS_GET_G(rccolor) << 8) | NS_GET_G(rccolor);
01463     aColor.color.blue = (NS_GET_B(rccolor) << 8) | NS_GET_B(rccolor);
01464     aColor.color.alpha = 0xffff;
01465 
01466     *aDraw = aSurface->GetXftDraw();
01467 
01468 //    fprintf (stderr, "+++ PrepareToDraw: %p\n", *aDraw);
01469 
01470     nsCOMPtr<nsIRegion> lastRegion;
01471     nsCOMPtr<nsIRegion> clipRegion;
01472 
01473     aSurface->GetLastXftClip(getter_AddRefs(lastRegion));
01474     aContext->GetClipRegion(getter_AddRefs(clipRegion));
01475 
01476     // avoid setting the clip, if possible
01477     if (!lastRegion || !clipRegion || !lastRegion->IsEqual(*clipRegion)) {
01478 #if 0 // XXX pavlov ugh...
01479         aSurface->SetLastXftClip(clipRegion);
01480 
01481         GdkRegion *rgn = nsnull;
01482         clipRegion->GetNativeRegion((void *&)rgn);
01483 
01484 #ifdef MOZ_WIDGET_GTK
01485         GdkRegionPrivate  *priv = (GdkRegionPrivate *)rgn;
01486         XftDrawSetClip(*aDraw, priv->xregion);
01487 #endif
01488 
01489 #ifdef MOZ_WIDGET_GTK2
01490         GdkRegionSetXftClip(rgn, *aDraw);
01491 #endif
01492 #endif
01493     }
01494 }
01495 
01496 nsresult
01497 nsFontMetricsXft::DrawStringCallback(const FcChar32 *aString, PRUint32 aLen,
01498                                      nsFontXft *aFont, void *aData)
01499 {
01500     DrawStringData *data = (DrawStringData *)aData;
01501 
01502     // If there was no font found for this character, just draw the
01503     // unknown glyph character
01504     if (!aFont) {
01505         SetupMiniFont();
01506 
01507         for (PRUint32 i = 0; i<aLen; i++) {
01508             // position in X is the location offset in the string plus
01509             // whatever offset is required for the spacing argument
01510             const FcChar32 ch = aString[i];
01511             nscoord x = data->x + data->xOffset;
01512             nscoord y = data->y;
01513 
01514             // convert this into device coordinates
01515             data->context->TransformCoord(&x, &y);
01516 
01517             DrawUnknownGlyph(ch, x, y + mMiniFontYOffset, &data->color,
01518                              data->draw);
01519 
01520             if (data->spacing) {
01521                 data->xOffset += *data->spacing;
01522                 data->spacing += IS_NON_BMP(ch) ? 2 : 1;
01523             }
01524             else {
01525                 data->xOffset +=
01526                     NSToCoordRound((mMiniFontWidth*(IS_NON_BMP(ch) ? 3 : 2) +
01527                                 mMiniFontPadding*(IS_NON_BMP(ch) ? 6:5)) *
01528                             data->p2t);
01529             }
01530         }
01531 
01532         // We're done.
01533         return NS_OK;
01534     }
01535 
01536     // actually process the specbuffer converting the input string
01537     // to custom font code if necessary.
01538     return aFont->DrawStringSpec(NS_CONST_CAST(FcChar32 *, aString), 
01539                                  aLen, data);
01540 }
01541 
01542 nsresult
01543 nsFontMetricsXft::TextDimensionsCallback(const FcChar32 *aString, PRUint32 aLen,
01544                                          nsFontXft *aFont, void *aData)
01545 {
01546     nsTextDimensions *dimensions = (nsTextDimensions *)aData;
01547 
01548     if (!aFont) {
01549         SetupMiniFont();
01550         for (PRUint32 i = 0; i<aLen; i++) {
01551             dimensions->width += 
01552                 mMiniFontWidth * (IS_NON_BMP(aString[i]) ? 3 : 2) +
01553                 mMiniFontPadding * (IS_NON_BMP(aString[i]) ? 6 : 5);
01554         }
01555 
01556         if (dimensions->ascent < mMiniFontAscent)
01557             dimensions->ascent = mMiniFontAscent;
01558         if (dimensions->descent < mMiniFontDescent)
01559             dimensions->descent = mMiniFontDescent;
01560 
01561         return NS_OK;
01562     }
01563 
01564     // get the metric after converting the input string to
01565     // custom font code if necessary.
01566     XGlyphInfo glyphInfo;
01567     nsresult rv = aFont->GetTextExtents32(aString, aLen, glyphInfo);
01568     NS_ENSURE_SUCCESS(rv, rv);
01569 
01570     dimensions->width += glyphInfo.xOff;
01571 
01572     nscoord tmpMaxAscent = aFont->GetMaxAscent();
01573     nscoord tmpMaxDescent = aFont->GetMaxDescent();
01574 
01575     if (dimensions->ascent < tmpMaxAscent)
01576         dimensions->ascent = tmpMaxAscent;
01577     if (dimensions->descent < tmpMaxDescent)
01578         dimensions->descent = tmpMaxDescent;
01579 
01580     return NS_OK;
01581 }
01582 
01583 nsresult
01584 nsFontMetricsXft::GetWidthCallback(const FcChar32 *aString, PRUint32 aLen,
01585                                    nsFontXft *aFont, void *aData)
01586 {
01587     nscoord *width = (nscoord*)aData;
01588 
01589     if (!aFont) {
01590         SetupMiniFont();
01591         for (PRUint32 i = 0; i < aLen; i++) {
01592             *width += mMiniFontWidth * (IS_NON_BMP(aString[i]) ? 3 : 2) + 
01593                       mMiniFontPadding * (IS_NON_BMP(aString[i]) ? 6 : 5);
01594         }
01595         return NS_OK;
01596     }
01597 
01598     *width += aFont->GetWidth32(aString, aLen);
01599     return NS_OK;
01600 }
01601 
01602 #ifdef MOZ_MATHML
01603 nsresult
01604 nsFontMetricsXft::BoundingMetricsCallback(const FcChar32 *aString, 
01605                                           PRUint32 aLen, nsFontXft *aFont, 
01606                                           void *aData)
01607 {
01608     BoundingMetricsData *data = (BoundingMetricsData *)aData;
01609     nsBoundingMetrics bm;
01610 
01611     if (!aFont) {
01612         SetupMiniFont();
01613 
01614         // Note:  All fields of bm initialized to 0 in its constructor.
01615         for (PRUint32 i = 0; i < aLen; i++) {
01616             bm.width += mMiniFontWidth * (IS_NON_BMP(aString[i]) ? 3 : 2) +
01617                         mMiniFontPadding * (IS_NON_BMP(aString[i]) ? 6 : 5);
01618             bm.rightBearing += bm.width; // no need to set leftBearing.
01619         }
01620         bm.ascent = mMiniFontAscent;
01621         bm.descent = mMiniFontDescent;
01622     }
01623     else {
01624         nsresult rv;
01625         rv = aFont->GetBoundingMetrics32(aString, aLen, bm);
01626         NS_ENSURE_SUCCESS(rv, rv);
01627     }
01628 
01629     if (data->firstTime) {  
01630         *(data->bm) = bm;
01631         data->firstTime = PR_FALSE;
01632     }
01633     else {
01634         *(data->bm) += bm;
01635     }
01636 
01637     return NS_OK;
01638 }
01639 #endif /* MOZ_MATHML */
01640 
01641 /* static */
01642 nsresult
01643 nsFontMetricsXft::FamilyExists(nsIDeviceContext *aDevice,
01644                                const nsString &aName)
01645 {
01646     // fontconfig family name is always in UTF-8
01647     NS_ConvertUTF16toUTF8 name(aName);
01648 
01649     FcFontSet *set = nsnull;
01650     FcObjectSet *os = nsnull;
01651 
01652     FcPattern *pat = FcPatternCreate();
01653     if (!pat)
01654         return NS_ERROR_FAILURE;
01655 
01656     nsresult rv = NS_ERROR_FAILURE;
01657     
01658     // Build a list of familes and walk the list looking to see if we
01659     // have it.
01660     os = FcObjectSetBuild(FC_FAMILY, 0);
01661     if (!os)
01662         goto end;
01663 
01664     set = FcFontList(0, pat, os);
01665 
01666     if (!set || !set->nfont)
01667         goto end;
01668 
01669     for (int i = 0; i < set->nfont; ++i) {
01670         const char *tmpname = NULL;
01671         if (FcPatternGetString(set->fonts[i], FC_FAMILY, 0,
01672                                (FcChar8 **)&tmpname) != FcResultMatch) {
01673             continue;
01674         }
01675 
01676         // do they match?
01677         if (!Compare(nsDependentCString(tmpname), name,
01678                      nsCaseInsensitiveCStringComparator())) {
01679             rv = NS_OK;
01680             break;
01681         }
01682     }
01683 
01684  end:
01685     if (set)
01686         FcFontSetDestroy(set);
01687     if (os)
01688         FcObjectSetDestroy(os);
01689 
01690     FcPatternDestroy(pat);
01691 
01692     return rv;
01693 }
01694 
01695 /* static */
01696 PRBool
01697 nsFontMetricsXft::EnumFontCallback(const nsString &aFamily, PRBool aIsGeneric,
01698                                    void *aData)
01699 {
01700     NS_ConvertUTF16toUTF8 name(aFamily);
01701 
01702     // The newest fontconfig does the full Unicode case folding so that 
01703     // we're being lazy here by calling |ToLowerCase| after converting
01704     // to UTF-8  assuming that in virtually all cases, we just have to
01705     // fold [A-Z].  (bug 223653). 
01706     ToLowerCase(name);
01707     nsFontMetricsXft *metrics = (nsFontMetricsXft *)aData;
01708     metrics->mFontList.AppendCString(name);
01709     metrics->mFontIsGeneric.AppendElement((void *)aIsGeneric);
01710     if (aIsGeneric) {
01711         metrics->mGenericFont = 
01712             metrics->mFontList.CStringAt(metrics->mFontList.Count() - 1);
01713         return PR_FALSE; // stop processing
01714     }
01715 
01716     return PR_TRUE; // keep processing
01717 }
01718 
01719 // nsFontEnumeratorXft class
01720 
01721 nsFontEnumeratorXft::nsFontEnumeratorXft()
01722 {
01723 }
01724 
01725 NS_IMPL_ISUPPORTS1(nsFontEnumeratorXft, nsIFontEnumerator)
01726 
01727 NS_IMETHODIMP
01728 nsFontEnumeratorXft::EnumerateAllFonts(PRUint32 *aCount, PRUnichar ***aResult)
01729 {
01730     NS_ENSURE_ARG_POINTER(aResult);
01731     *aResult = nsnull;
01732     NS_ENSURE_ARG_POINTER(aCount);
01733     *aCount = 0;
01734 
01735     return EnumFontsXft(nsnull, nsnull, aCount, aResult);
01736 }
01737 
01738 NS_IMETHODIMP
01739 nsFontEnumeratorXft::EnumerateFonts(const char *aLangGroup,
01740                                     const char *aGeneric,
01741                                     PRUint32 *aCount, PRUnichar ***aResult)
01742 {
01743     NS_ENSURE_ARG_POINTER(aResult);
01744     *aResult = nsnull;
01745     NS_ENSURE_ARG_POINTER(aCount);
01746     *aCount = 0;
01747 
01748     // aLangGroup=null or ""  means any (i.e., don't care)
01749     // aGeneric=null or ""  means any (i.e, don't care)
01750     nsCOMPtr<nsIAtom> langGroup;
01751     if (aLangGroup && *aLangGroup)
01752       langGroup = do_GetAtom(aLangGroup);
01753     const char* generic = nsnull;
01754     if (aGeneric && *aGeneric)
01755       generic = aGeneric;
01756 
01757     return EnumFontsXft(langGroup, generic, aCount, aResult);
01758 }
01759 
01760 NS_IMETHODIMP
01761 nsFontEnumeratorXft::HaveFontFor(const char *aLangGroup, PRBool *aResult)
01762 {
01763     NS_ENSURE_ARG_POINTER(aResult);
01764     *aResult = PR_FALSE;
01765     NS_ENSURE_ARG_POINTER(aLangGroup);
01766 
01767     *aResult = PR_TRUE; // always return true for now.
01768     // Finish me - ftang
01769     return NS_OK;
01770 }
01771 
01772 NS_IMETHODIMP
01773 nsFontEnumeratorXft::GetDefaultFont(const char *aLangGroup, 
01774   const char *aGeneric, PRUnichar **aResult)
01775 {
01776   // aLangGroup=null or ""  means any (i.e., don't care)
01777   // aGeneric=null or ""  means any (i.e, don't care)
01778 
01779   NS_ENSURE_ARG_POINTER(aResult);
01780   *aResult = nsnull;
01781 
01782 #if 0
01783   //XXX Some voodoo inspired from the thread:
01784   //XXX http://www.mail-archive.com/fonts@xfree86.org/msg01344.html
01785   //XXX please iterate to turn this on when you are happy/ready
01786 
01787   FcResult res;
01788   FcPattern* match_pattern = NULL;
01789   if (aGeneric && *aGeneric)
01790     match_pattern = FcNameParse(aGeneric);
01791   else
01792     match_pattern = FcPatternCreate();
01793 
01794   if (!match_pattern)
01795     return NS_OK; // not fatal, just return an empty default name
01796 
01797   if (aLangGroup && *aLangGroup) {
01798     nsCOMPtr<nsIAtom> langGroup = do_GetAtom(aLangGroup);
01799     NS_AddLangGroup(match_pattern, langGroup);
01800   }
01801 
01802   FcConfigSubstitute(0, match_pattern, FcMatchPattern); 
01803   FcDefaultSubstitute(match_pattern);
01804   FcPattern* result_pattern = FcFontMatch(0, match_pattern, &res);
01805   if (result_pattern) {
01806     char *family;
01807     FcPatternGetString(result_pattern, FC_FAMILY, 0, (FcChar8 **)&family);
01808     PRUnichar* name = NS_STATIC_CAST(PRUnichar *,
01809                               nsMemory::Alloc ((strlen (family) + 1)
01810                                                * sizeof (PRUnichar)));
01811     if (name) {
01812       PRUnichar *r = name;
01813       for (char *f = family; *f; ++f)
01814         *r++ = *f;
01815       *r = '\0';
01816 
01817       *aResult = name;
01818     }
01819 
01820     FcPatternDestroy(result_pattern);
01821   }
01822   FcPatternDestroy(match_pattern);
01823 #endif
01824 
01825   return NS_OK;
01826 }
01827 
01828 NS_IMETHODIMP
01829 nsFontEnumeratorXft::UpdateFontList(PRBool *_retval)
01830 {
01831     *_retval = PR_FALSE; // always return false for now
01832     return NS_OK;
01833 }
01834 
01835 // class nsFontXft
01836 
01837 nsFontXft::nsFontXft(FcPattern *aPattern, FcPattern *aFontName)
01838 {
01839     // save our pattern - we own it now
01840     mPattern = aPattern;
01841     mFontName = aFontName;
01842     // don't destroy it out from under us
01843     FcPatternReference(aPattern);
01844     FcPatternReference(mFontName);
01845 
01846     mXftFont = nsnull;
01847 
01848     // set up our charset
01849     mCharset = nsnull;
01850     FcCharSet *charset = nsnull;
01851 
01852     // this references an internal charset, we need to copy it
01853     FcPatternGetCharSet(aFontName, FC_CHARSET, 0, &charset);
01854     if (charset)
01855         mCharset = FcCharSetCopy(charset);
01856 }
01857 
01858 nsFontXft::~nsFontXft()
01859 {
01860     if (mXftFont)
01861         XftFontClose(GDK_DISPLAY(), mXftFont);
01862     if (mCharset)
01863         FcCharSetDestroy(mCharset);
01864     if (mPattern)
01865         FcPatternDestroy(mPattern);
01866     if (mFontName)
01867         FcPatternDestroy(mFontName);
01868 }
01869 
01870 XftFont *
01871 nsFontXft::GetXftFont(void)
01872 {
01873     if (!mXftFont) {
01874         FcPattern *pat = FcFontRenderPrepare(0, mPattern, mFontName);
01875         if (!pat)
01876             return nsnull;
01877 
01878         // bug 196312 : work around problem with CJK bi-width fonts
01879         // and fontconfig prior to 2.2. CJK bi-width fonts are regarded
01880         // as genuinely monospace by fontconfig that  sets FC_SPACING
01881         // to FC_MONOSPACE, which makes Xft drawing/measuring routines
01882         // use the global advance width (the width of double width glyphs 
01883         // and twice the width of single width glyphs) even for single width
01884         // characters (e.g. Latin letters and digits). This results in
01885         // spaced-out ('s p a c e d - o u t') rendering. By deleting
01886         // FC_SPACING here, we're emulating the behavior of fontconfig 2.2 or 
01887         // later that does not set FC_SPACING for any font.
01888         if (FcGetVersion() < 20300)
01889             FcPatternDel(pat, FC_SPACING);
01890 
01891         mXftFont = XftFontOpenPattern(GDK_DISPLAY(), pat);
01892         if (!mXftFont)
01893             FcPatternDestroy(pat);
01894     }
01895 
01896     return mXftFont;
01897 }
01898 
01899 // used by GetWidth32, GetBoundingMetrics32, and TextDimensionCallback
01900 nsresult
01901 nsFontXft::GetTextExtents32(const FcChar32 *aString, PRUint32 aLen, 
01902                             XGlyphInfo &aGlyphInfo)
01903 {
01904     NS_PRECONDITION(mXftFont, "FindFont should not return bad fonts");
01905 
01906     // NS_CONST_CAST needed for older versions of Xft
01907     XftTextExtents32(GDK_DISPLAY(), mXftFont,
01908                      NS_CONST_CAST(FcChar32*, aString), aLen, &aGlyphInfo);
01909 
01910     return NS_OK;
01911 }
01912 
01913 gint
01914 nsFontXft::GetWidth32(const FcChar32 *aString, PRUint32 aLen)
01915 {
01916     XGlyphInfo glyphInfo;
01917     GetTextExtents32(aString, aLen, glyphInfo);
01918 
01919     return glyphInfo.xOff;
01920 }
01921 
01922 #ifdef MOZ_MATHML
01923 nsresult
01924 nsFontXft::GetBoundingMetrics32(const FcChar32*    aString,
01925                                 PRUint32           aLength,
01926                                 nsBoundingMetrics& aBoundingMetrics)
01927 {
01928     aBoundingMetrics.Clear ();
01929 
01930     if (aString && aLength) {
01931         XGlyphInfo glyphInfo;
01932         GetTextExtents32 (aString, aLength, glyphInfo);
01933         aBoundingMetrics.leftBearing = - glyphInfo.x;
01934         aBoundingMetrics.rightBearing = glyphInfo.width - glyphInfo.x;
01935         aBoundingMetrics.ascent = glyphInfo.y;
01936         aBoundingMetrics.descent = glyphInfo.height - glyphInfo.y;
01937         aBoundingMetrics.width = glyphInfo.xOff;
01938     }
01939     return NS_OK;
01940 }
01941 #endif /* MOZ_MATHML */
01942 
01943 PRInt16
01944 nsFontXft::GetMaxAscent(void)
01945 {
01946     NS_PRECONDITION(mXftFont, "FindFont should not return bad fonts");
01947 
01948     return mXftFont->ascent;
01949 }
01950 
01951 PRInt16
01952 nsFontXft::GetMaxDescent(void)
01953 {
01954     NS_PRECONDITION(mXftFont, "FindFont should not return bad fonts");
01955     return mXftFont->descent;
01956 }
01957 
01958 FT_UInt
01959 nsFontXft::CharToGlyphIndex(FcChar32 aChar)
01960 {
01961     return XftCharIndex(GDK_DISPLAY(), mXftFont, aChar);
01962 }
01963 
01964 // used by DrawStringCallback
01965 nsresult
01966 nsFontXft::DrawStringSpec(FcChar32 *aString, PRUint32 aLen, void *aData)
01967 {
01968     NS_PRECONDITION(mXftFont, "FindFont should not return bad fonts");
01969     DrawStringData *data = (DrawStringData *)aData;
01970 
01971     FcChar32 *pstr = aString;
01972     const FcChar32 *end = aString + aLen;
01973 
01974     while(pstr < end) {
01975         nscoord x = data->x + data->xOffset;
01976         nscoord y = data->y;
01977         /* Convert to device coordinate. */
01978 //        fprintf (stderr, "[%d %d -> ", x, y);
01979         data->context->TransformCoord(&x, &y);
01980 //        fprintf (stderr, "%d %d] ", x, y);
01981 
01982         /* position in X is the location offset in the string 
01983            plus whatever offset is required for the spacing   
01984            argument                                           
01985         */                                                  
01986 
01987         FT_UInt glyph = CharToGlyphIndex(*pstr);
01988         data->drawBuffer->Draw(x, y, mXftFont, glyph);
01989 
01990         if (data->spacing) {
01991             data->xOffset += *data->spacing;
01992             data->spacing += IS_NON_BMP(*pstr) ? 2 : 1; 
01993         }
01994         else {
01995             XGlyphInfo info;                        
01996             XftGlyphExtents(GDK_DISPLAY(), mXftFont, &glyph, 1, &info);
01997             data->xOffset += NSToCoordRound(info.xOff * data->p2t);
01998         }
01999 
02000         ++pstr;
02001     }
02002     return NS_OK;
02003 }
02004 
02005 // class nsFontXftUnicode impl
02006   
02007 nsFontXftUnicode::~nsFontXftUnicode()
02008 {
02009 }
02010 
02011 PRBool
02012 nsFontXftUnicode::HasChar(PRUint32 aChar)
02013 {
02014     return FcCharSetHasChar(mCharset, (FcChar32) aChar);
02015 }
02016 
02017 // class nsFontXftCustom impl
02018 
02019 nsFontXftCustom::~nsFontXftCustom()
02020 {
02021     if (mXftFont && mFT_Face)
02022        XftUnlockFace(mXftFont);
02023 }
02024 
02025 // used by GetWidth32, GetBoundingMetrics32, and TextDimensionCallback
02026 // Convert the input to custom font code before measuring.
02027 nsresult
02028 nsFontXftCustom::GetTextExtents32(const FcChar32 *aString, PRUint32 aLen, 
02029                                   XGlyphInfo &aGlyphInfo)
02030 {
02031     NS_PRECONDITION(mXftFont, "FindFont should not return bad fonts");
02032 
02033     nsAutoFcChar32Buffer buffer;
02034     nsresult rv;
02035     PRUint32 destLen = aLen;
02036     PRBool isWide = (mFontInfo->mFontType == eFontTypeCustomWide); 
02037 
02038     // we won't use this again. it's safe to cast away const.
02039     rv = ConvertUCS4ToCustom(NS_CONST_CAST(FcChar32 *, aString), 
02040                              aLen, destLen, mFontInfo->mConverter,
02041                              isWide, buffer);
02042     NS_ENSURE_SUCCESS(rv, rv);
02043       
02044     FcChar32 *str = buffer.get();
02045 
02046     // short cut for the common case
02047     if (isWide) { 
02048         XftTextExtents32(GDK_DISPLAY(), mXftFont, str, destLen, &aGlyphInfo);
02049         return NS_OK;
02050     }
02051 
02052     // If FT_SelectCharMap succeeds for MacRoman or Unicode,
02053     // use glyph indices directly for 'narrow' custom encoded fonts.
02054     rv = SetFT_FaceCharmap();
02055     NS_ENSURE_SUCCESS(rv, rv);
02056 
02057     // replace chars with glyphs in place. 
02058     for (PRUint32 i = 0; i < destLen; i++) {
02059         str[i] = FT_Get_Char_Index (mFT_Face, FT_ULong(str[i]));
02060     }
02061 
02062     XftGlyphExtents(GDK_DISPLAY(), mXftFont, str, destLen, &aGlyphInfo);
02063         
02064     return NS_OK;
02065 }
02066 
02067 PRBool
02068 nsFontXftCustom::HasChar(PRUint32 aChar)
02069 {
02070     return (mFontInfo->mCCMap &&
02071             CCMAP_HAS_CHAR_EXT(mFontInfo->mCCMap, aChar)); 
02072 }
02073 
02074 FT_UInt
02075 nsFontXftCustom::CharToGlyphIndex(FcChar32 aChar)
02076 {
02077     if (mFontInfo->mFontType == eFontTypeCustomWide)
02078         return XftCharIndex(GDK_DISPLAY(), mXftFont, aChar);
02079     else
02080         return FT_Get_Char_Index(mFT_Face, aChar);
02081 }
02082 
02083 // used by DrawStringCallback
02084 // Convert the input to custom font code before filling up the buffer.
02085 nsresult
02086 nsFontXftCustom::DrawStringSpec(FcChar32* aString, PRUint32 aLen,
02087                                 void* aData)
02088 {
02089     NS_PRECONDITION(mXftFont, "FindFont should not return bad fonts");
02090 
02091     nsresult rv = NS_OK;
02092     nsAutoFcChar32Buffer buffer;
02093     PRUint32 destLen = aLen;
02094     PRBool isWide = (mFontInfo->mFontType == eFontTypeCustomWide); 
02095 
02096     rv = ConvertUCS4ToCustom(aString, aLen, destLen, mFontInfo->mConverter, 
02097                              isWide, buffer);
02098     NS_ENSURE_SUCCESS(rv, rv);
02099 
02100     if (!isWide) {
02101         // For some narrow fonts(Mathematica, Symbol, and MTExtra),  
02102         // what we get back  after the conversion  is in the encoding 
02103         // of a specific  FT_Charmap (Apple Roman) instead of Unicode 
02104         // so that we  can't call XftCharIndex() which regards input 
02105         // as a Unicode codepoint. Instead, we have to directly invoke 
02106         // FT_Get_Char_Index() with FT_Face corresponding to XftFont 
02107         // after setting FT_Charmap to the cmap of our choice(Apple Roman).
02108         rv = SetFT_FaceCharmap();
02109         NS_ENSURE_SUCCESS(rv, rv);
02110     }
02111 
02112     FcChar32 *str = buffer.get();
02113 
02114     return nsFontXft::DrawStringSpec(str, destLen, aData);
02115 }
02116 
02117 nsresult
02118 nsFontXftCustom::SetFT_FaceCharmap(void)
02119 {
02120     NS_PRECONDITION(mXftFont, "FindFont should not return bad fonts");
02121 
02122     if (mFT_Face)
02123         return NS_OK;
02124 
02125     mFT_Face = XftLockFace(mXftFont);
02126 
02127     NS_ENSURE_TRUE(mFT_Face != nsnull, NS_ERROR_UNEXPECTED);
02128 
02129     // Select FT_Encoding to use for custom narrow fonts in 
02130     // glyph index look-up with FT_Get_Char_Index succeeds.
02131         
02132     if (FT_Select_Charmap (mFT_Face, mFontInfo->mFT_Encoding))
02133         return NS_ERROR_UNEXPECTED;
02134 
02135     return NS_OK;
02136 }
02137 
02138 void
02139 nsAutoDrawSpecBuffer::Draw(nscoord x, nscoord y, XftFont *font, FT_UInt glyph)
02140 {
02141     if (mSpecPos >= BUFFER_LEN-1)
02142         Flush();
02143 
02144     mSpecBuffer[mSpecPos].x = x;
02145     mSpecBuffer[mSpecPos].y = y;
02146     mSpecBuffer[mSpecPos].font = font;
02147     mSpecBuffer[mSpecPos].glyph = glyph;
02148     ++mSpecPos;
02149 }
02150 
02151 void
02152 nsAutoDrawSpecBuffer::Flush()
02153 {
02154     if (mSpecPos) {
02155         // Some Xft libraries will crash if none of the glyphs have any
02156         // area.  So before we draw, we scan through the glyphs.  If we
02157         // find any that have area, we can draw.
02158         for (PRUint32 i = 0; i < mSpecPos; i++) {
02159             XftGlyphFontSpec *sp = &mSpecBuffer[i];
02160             XGlyphInfo info;
02161             XftGlyphExtents(GDK_DISPLAY(), sp->font, &sp->glyph, 1, &info);
02162             if (info.width && info.height) {
02163                 // If we get here it means we found a drawable glyph.  We will
02164                 // Draw all the remaining glyphs and then break out of the loop
02165                 XftDrawGlyphFontSpec(mDraw, mColor, mSpecBuffer+i, mSpecPos-i);
02166                 break;
02167             }
02168         }
02169         mSpecPos = 0;
02170     }
02171 }
02172 
02173 // Static functions
02174 
02175 /* static */
02176 int
02177 CompareFontNames (const void* aArg1, const void* aArg2, void* aClosure)
02178 {
02179     const PRUnichar* str1 = *((const PRUnichar**) aArg1);
02180     const PRUnichar* str2 = *((const PRUnichar**) aArg2);
02181 
02182     return nsCRT::strcmp(str1, str2);
02183 }
02184 
02185 /* static */
02186 nsresult
02187 EnumFontsXft(nsIAtom* aLangGroup, const char* aGeneric,
02188              PRUint32* aCount, PRUnichar*** aResult)
02189 {
02190     FcPattern   *pat = NULL;
02191     FcObjectSet *os  = NULL;
02192     FcFontSet   *fs  = NULL;
02193     nsresult     rv  = NS_ERROR_FAILURE;
02194 
02195     PRUnichar **array = NULL;
02196     PRUint32    narray = 0;
02197     PRInt32     serif = 0, sansSerif = 0, monospace = 0, nGenerics;
02198 
02199     *aCount = 0;
02200     *aResult = nsnull;
02201 
02202     pat = FcPatternCreate();
02203     if (!pat)
02204         goto end;
02205 
02206     os = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, 0);
02207     if (!os)
02208         goto end;
02209 
02210     // take the pattern and add the lang group to it
02211     if (aLangGroup)
02212         NS_AddLangGroup(pat, aLangGroup);
02213 
02214     // get the font list
02215     fs = FcFontList(0, pat, os);
02216 
02217     if (!fs)
02218         goto end;
02219 
02220     if (!fs->nfont) {
02221         rv = NS_OK;
02222         goto end;
02223     }
02224 
02225     // Fontconfig supports 3 generic fonts, "serif", "sans-serif", and
02226     // "monospace", slightly different from CSS's 5.
02227     if (!aGeneric)
02228         serif = sansSerif = monospace = 1;
02229     else if (!strcmp(aGeneric, "serif"))
02230         serif = 1;
02231     else if (!strcmp(aGeneric, "sans-serif"))
02232         sansSerif = 1;
02233     else if (!strcmp(aGeneric, "monospace"))
02234         monospace = 1;
02235     else if (!strcmp(aGeneric, "cursive") || !strcmp(aGeneric, "fantasy"))
02236         serif = sansSerif =  1;
02237     else
02238         NS_NOTREACHED("unexpected generic family");
02239     nGenerics = serif + sansSerif + monospace;
02240 
02241     array = NS_STATIC_CAST(PRUnichar **,
02242                nsMemory::Alloc((fs->nfont + nGenerics) * sizeof(PRUnichar *)));
02243     if (!array)
02244         goto end;
02245 
02246     if (serif) {
02247         PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("serif"));
02248         if (!name)
02249             goto end;
02250         array[narray++] = name;
02251     }
02252 
02253     if (sansSerif) {
02254         PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("sans-serif"));
02255         if (!name)
02256             goto end;
02257         array[narray++] = name;
02258     }
02259 
02260     if (monospace) {
02261         PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("monospace"));
02262         if (!name)
02263             goto end;
02264         array[narray++] = name;
02265     }
02266 
02267     for (int i=0; i < fs->nfont; ++i) {
02268         char *family;
02269 
02270         // if there's no family, just move to the next iteration
02271         if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
02272                                 (FcChar8 **) &family) != FcResultMatch) {
02273             continue;
02274         }
02275 
02276         // fontconfig always returns family names in UTF-8
02277         PRUnichar* name =  UTF8ToNewUnicode(nsDependentCString(family));
02278 
02279         if (!name)
02280             goto end;
02281 
02282         array[narray++] = name;
02283     }
02284 
02285     NS_QuickSort(array + nGenerics, narray - nGenerics, sizeof (PRUnichar*),
02286                  CompareFontNames, nsnull);
02287 
02288     *aCount = narray;
02289     if (narray)
02290         *aResult = array;
02291     else
02292         nsMemory::Free(array);
02293 
02294     rv = NS_OK;
02295 
02296  end:
02297     if (NS_FAILED(rv) && array) {
02298         while (narray)
02299             nsMemory::Free (array[--narray]);
02300         nsMemory::Free (array);
02301     }
02302     if (pat)
02303         FcPatternDestroy(pat);
02304     if (os)
02305         FcObjectSetDestroy(os);
02306     if (fs)
02307         FcFontSetDestroy(fs);
02308 
02309     return rv;
02310 }
02311 
02312 /* static */
02313 void
02314 ConvertCharToUCS4(const char *aString, PRUint32 aLength, 
02315                   nsAutoFcChar32Buffer &aOutBuffer, PRUint32 *aOutLen)
02316 {
02317     *aOutLen = 0;
02318     FcChar32 *outBuffer;
02319 
02320     if (!aOutBuffer.EnsureElemCapacity(aLength))
02321         return;
02322     outBuffer  = aOutBuffer.get();
02323     
02324     for (PRUint32 i = 0; i < aLength; ++i) {
02325         outBuffer[i] = PRUint8(aString[i]); // to convert char >= 0x80 correctly
02326     }
02327 
02328     *aOutLen = aLength;
02329 }
02330 
02331 // Convert the incoming string into an array of UCS4 chars
02332   
02333 /* static */
02334 void
02335 ConvertUnicharToUCS4(const PRUnichar *aString, PRUint32 aLength,
02336                      nsAutoFcChar32Buffer &aOutBuffer, PRUint32 *aOutLen)
02337 {
02338     *aOutLen = 0;
02339     FcChar32 *outBuffer;
02340 
02341     if (!aOutBuffer.EnsureElemCapacity(aLength))
02342         return;
02343     outBuffer  = aOutBuffer.get();
02344 
02345     PRUint32 outLen = 0;
02346 
02347     // Walk the passed in string looking for surrogates to convert to
02348     // their full ucs4 representation.
02349     for (PRUint32 i = 0; i < aLength; ++i) {
02350         PRUnichar c = aString[i];
02351 
02352         // Optimized for the non-surrogate case
02353         if (IS_NON_SURROGATE(c)) {
02354             outBuffer[outLen] = c;
02355         }
02356         else if (IS_HIGH_SURROGATE(aString[i])) {
02357             if (i + 1 < aLength && IS_LOW_SURROGATE(aString[i+1])) {
02358                 outBuffer[outLen] = SURROGATE_TO_UCS4(c, aString[i + 1]);
02359                 ++i;
02360             }
02361             else { // Unpaired high surrogate
02362                 outBuffer[outLen] = UCS2_REPLACEMENT;
02363             }
02364         }
02365         else if (IS_LOW_SURROGATE(aString[i])) { // Unpaired low surrogate?
02366             outBuffer[outLen] = UCS2_REPLACEMENT;
02367         }
02368 
02369         outLen++;
02370     }
02371 
02372     *aOutLen = outLen;
02373 }
02374 
02375 #ifdef MOZ_WIDGET_GTK2
02376 /* static */
02377 void
02378 GdkRegionSetXftClip(GdkRegion *aGdkRegion, XftDraw *aDraw)
02379 {
02380     GdkRectangle  *rects   = nsnull;
02381     int            n_rects = 0;
02382 
02383     gdk_region_get_rectangles(aGdkRegion, &rects, &n_rects);
02384 
02385     XRectangle *xrects = g_new(XRectangle, n_rects);
02386 
02387     for (int i=0; i < n_rects; ++i) {
02388         xrects[i].x = CLAMP(rects[i].x, G_MINSHORT, G_MAXSHORT);
02389         xrects[i].y = CLAMP(rects[i].y, G_MINSHORT, G_MAXSHORT);
02390         xrects[i].width = CLAMP(rects[i].width, G_MINSHORT, G_MAXSHORT);
02391         xrects[i].height = CLAMP(rects[i].height, G_MINSHORT, G_MAXSHORT);
02392     }
02393 
02394     XftDrawSetClipRectangles(aDraw, 0, 0, xrects, n_rects);
02395 
02396     g_free(xrects);
02397     g_free(rects);
02398 }
02399 #endif /* MOZ_WIDGET_GTK2 */
02400 
02401 // Helper to determine if a font has a private encoding that we know
02402 // something about
02403 /* static */
02404 nsresult
02405 GetEncoding(const char *aFontName, char **aEncoding, nsXftFontType &aType,
02406             FT_Encoding &aFTEncoding)
02407 {
02408   // below is a list of common used name for startup
02409     if ((!strcmp(aFontName, "Helvetica" )) ||
02410          (!strcmp(aFontName, "Times" )) ||
02411          (!strcmp(aFontName, "Times New Roman" )) ||
02412          (!strcmp(aFontName, "Courier New" )) ||
02413          (!strcmp(aFontName, "Courier" )) ||
02414          (!strcmp(aFontName, "Arial" )) ||
02415          (!strcmp(aFontName, "MS P Gothic" )) ||
02416         (!strcmp(aFontName, "Verdana" ))) {
02417         // error mean do not get a special encoding
02418         return NS_ERROR_NOT_AVAILABLE; 
02419     }
02420 
02421     nsCAutoString name;
02422     name.Assign(NS_LITERAL_CSTRING("encoding.") + 
02423                 nsDependentCString(aFontName) + NS_LITERAL_CSTRING(".ttf"));
02424 
02425     name.StripWhitespace();
02426     ToLowerCase(name);
02427 
02428     // if we have not init the property yet, init it right now.
02429     if (!gFontEncodingProperties)
02430         NS_LoadPersistentPropertiesFromURISpec(&gFontEncodingProperties,
02431             NS_LITERAL_CSTRING("resource://gre/res/fonts/fontEncoding.properties"));
02432 
02433     nsAutoString encoding;
02434     *aEncoding = nsnull;
02435     if (gFontEncodingProperties) {
02436         nsresult rv = gFontEncodingProperties->GetStringProperty(name,
02437                                                                  encoding);
02438         if (NS_FAILED(rv)) 
02439             return NS_ERROR_NOT_AVAILABLE;  // Unicode font
02440 
02441         // '.wide' at the end indicates 'wide' font.
02442         if (encoding.Length() > 5 && 
02443             StringEndsWith(encoding, NS_LITERAL_STRING(".wide"))) {
02444             aType = eFontTypeCustomWide;
02445             encoding.Truncate(encoding.Length() - 5);
02446         }
02447         else  {
02448             aType = eFontTypeCustom;
02449 
02450             // Mathematica and TeX CM truetype fonts have both Apple Roman
02451             // (PID=1, EID=0) and Unicode (PID=3, EID=1) cmaps. In the
02452             // former, Unicode cmap uses codepoints in PUA beginning
02453             // at U+F000 not representable in a single byte encoding
02454             // like MathML encodings. ( On the other hand, TeX CM fonts
02455             // have 'pseudo-Unicode' cmap with codepoints below U+0100.)
02456             // Unicode to font encoding converters for MathML map input 
02457             // Unicode codepoints to 'pseudo-glyph indices' in Apple Roman 
02458             // for  Mathematica, Symbol and MTExtra fonts while it maps
02459             // input Unicode codepoints  to 'pseudo-glyph indices' in 
02460             // 'Unicode cmap' for TeX CM fonts. Therefore we have to select
02461             // different FT_Encoding for two groups to guarantee that
02462             // glyph index look-up with FT_Get_Char_Index succeeds for
02463             // all MathML fonts. Instead of hard-coding this relation,
02464             // it's put in fontEncoding.properties file and is parsed here.
02465           
02466             nsAutoString ftCharMap; 
02467             nsresult rv = gFontEncodingProperties->GetStringProperty(
02468                           Substring(name, 0, name.Length() - 4) + 
02469                           NS_LITERAL_CSTRING(".ftcmap"), ftCharMap);
02470           
02471             if (NS_FAILED(rv)) 
02472                 aFTEncoding = ft_encoding_none;
02473             else if (ftCharMap.LowerCaseEqualsLiteral("mac_roman"))
02474                 aFTEncoding = ft_encoding_apple_roman;
02475             else if (ftCharMap.LowerCaseEqualsLiteral("unicode"))
02476                 aFTEncoding = ft_encoding_unicode;
02477         }
02478 
02479         // encoding name is always in US-ASCII so that there's no loss here.
02480         *aEncoding = ToNewCString(encoding);
02481         if (PR_LOG_TEST(gXftFontLoad, PR_LOG_DEBUG)) {
02482           printf("\t\tc> it's %s and encoding is %s\n",
02483                   aType==eFontTypeCustom ? "narrow" : "wide", *aEncoding);
02484         }
02485 
02486         return NS_OK;
02487     }
02488 
02489     return NS_ERROR_NOT_AVAILABLE;
02490 }
02491 
02492 /* static */
02493 static nsresult
02494 GetConverter(const char* aEncoding, nsIUnicodeEncoder **aConverter)
02495 {
02496     nsresult rv;
02497 
02498     if (!gCharsetManager) {
02499         CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
02500         if (!gCharsetManager) {
02501             FreeGlobals();
02502             return NS_ERROR_FAILURE;
02503         }
02504     }
02505 
02506     // encoding name obtained from fontEncoding.properties is
02507     // canonical so that we don't need the alias resolution. use 'Raw'
02508     // version.
02509     rv = gCharsetManager->GetUnicodeEncoderRaw(aEncoding, aConverter);
02510     NS_ENSURE_SUCCESS(rv, rv);
02511     if (PR_LOG_TEST(gXftFontLoad, PR_LOG_DEBUG)) {
02512         printf("\t\tc> got the converter for %s \n", aEncoding);
02513     }
02514 
02515     return (*aConverter)->SetOutputErrorBehavior(
02516             (*aConverter)->kOnError_Replace, nsnull, '?');
02517 }
02518 
02519 
02520 /* static */
02521 nsresult
02522 FreeGlobals(void)
02523 {
02524     gInitialized = 0;
02525 
02526     NS_IF_RELEASE(gFontEncodingProperties);
02527     NS_IF_RELEASE(gCharsetManager);
02528 
02529     gFontXftMaps.Clear();
02530 
02531     return NS_OK;
02532 }
02533 
02534 nsFontXftInfo*
02535 GetFontXftInfo(FcPattern* aPattern)
02536 {
02537     const char* family;
02538 
02539     // If there's no family, just treat it as if it's a normal Unicode font
02540     if (FcPatternGetString(aPattern, FC_FAMILY, 0, (FcChar8 **) &family) 
02541          != FcResultMatch) {
02542         return nsnull;
02543     }
02544 
02545     NS_ASSERTION(gFontXftMaps.IsInitialized(), "gFontXMaps should be init'd by now.");
02546 
02547     nsFontXftInfo* info;
02548 
02549     // cached entry found. 
02550     if (gFontXftMaps.Get(family, &info))
02551         return info;
02552 
02553     nsCOMPtr<nsIUnicodeEncoder> converter;
02554     nsXftFontType fontType =  eFontTypeUnicode; 
02555     nsXPIDLCString encoding;
02556     FT_Encoding ftEncoding = ft_encoding_unicode;
02557     PRUint16* ccmap = nsnull;
02558 
02559     // See if a font has a custom/private encoding by matching
02560     // its family name against the list in fontEncoding.properties 
02561     // with GetEncoding(). It also sets fonttype (wide or narrow). 
02562     // Then get the converter and see if has a valid coverage map. 
02563     
02564     // XXX these two if-statements used to be logically AND'ed, but
02565     // string changes (bug 231995) made it impossible to use getter_Copies(encoding)
02566     // and encoding.get() in a single statement. Until Darin comes up with 
02567     // a solution, we need to split it into two if-statements. (bug 234908)
02568     if (NS_SUCCEEDED(GetEncoding(family, getter_Copies(encoding), 
02569                      fontType, ftEncoding))) {
02570         if (NS_SUCCEEDED(GetConverter(encoding.get(), 
02571                          getter_AddRefs(converter)))) {
02572             nsCOMPtr<nsICharRepresentable> mapper(do_QueryInterface(converter));
02573             if (PR_LOG_TEST(gXftFontLoad, PR_LOG_DEBUG)) {
02574                printf("\t\tc> got the converter and CMap :%s !!\n",
02575                       encoding.get());
02576             }
02577 
02578             if (mapper) {
02579                 ccmap = MapperToCCMap(mapper);
02580             }
02581         }
02582     }
02583 
02584     // XXX Need to check if an identical map has already been added - Bug 75260
02585     // For Xft, this doesn't look as critical as in GFX Win.
02586 
02587     info = new nsFontXftInfo; 
02588     if (!info) 
02589         return nsnull; 
02590 
02591     info->mCCMap =  ccmap;  
02592     info->mConverter = converter;
02593     info->mFontType = fontType;
02594     info->mFT_Encoding = ftEncoding;
02595 
02596     gFontXftMaps.Put(family, info); 
02597 
02598     return info;
02599 }
02600 
02601 /* static */
02602 // Convert input UCS4 string to "Pseudo-UCS4" string made of
02603 // custom font-specific codepoints with Unicode converter.
02604 nsresult
02605 ConvertUCS4ToCustom(FcChar32 *aSrc,  PRUint32 aSrcLen,
02606                     PRUint32& aDestLen, nsIUnicodeEncoder *aConverter,
02607                     PRBool aIsWide, nsAutoFcChar32Buffer& aResult)
02608 {
02609     nsresult rv = NS_OK;
02610 
02611     nsCOMPtr<nsIUnicodeEncoder> converter = aConverter;
02612     if (!converter )
02613         return NS_ERROR_UNEXPECTED;
02614 
02615     // Convert to UTF-16 because UnicodeEncoder expects input to be in
02616     // UTF-16.  We can get away with in-place replacement because
02617     // UTF-16 is at most as long as UCS-4 so that UCS-4(source) buffer
02618     // pointer is always ahead of UTF-16(target) buffer pointer and we
02619     // won't revisit the buffer we already processed.
02620     
02621     PRUnichar *utf16Src  = NS_REINTERPRET_CAST(PRUnichar *, aSrc);
02622     PRUnichar *utf16Ptr = utf16Src;
02623     for (PRUint32 i = 0; i < aSrcLen; ++i, ++utf16Ptr) {
02624         if (!IS_NON_BMP(aSrc[i])) {
02625             *utf16Ptr = PRUnichar(aSrc[i]);
02626         }
02627         else {
02628             *utf16Ptr = H_SURROGATE(aSrc[i]);
02629             *++utf16Ptr = L_SURROGATE(aSrc[i]);
02630         }
02631     }
02632 
02633     PRInt32 utf16SrcLen = utf16Ptr - utf16Src;
02634     PRInt32 medLen = utf16SrcLen;
02635     // Length can increase for 'Wide' custom fonts.
02636     if (aIsWide &&
02637         NS_FAILED(aConverter->GetMaxLength(utf16Src, utf16SrcLen, &medLen))) {
02638         return NS_ERROR_UNEXPECTED;
02639     }
02640 
02641     nsAutoBuffer<char, AUTO_BUFFER_SIZE> medBuffer;
02642     if (!medBuffer.EnsureElemCapacity(medLen))
02643         return NS_ERROR_OUT_OF_MEMORY;
02644     char *med  = medBuffer.get();
02645 
02646     // Convert utf16Src  to font-specific encoding with mConverter.
02647     rv = converter->Convert(utf16Src, &utf16SrcLen, med, &medLen);
02648     NS_ENSURE_SUCCESS(rv, rv);
02649 
02650     // Put pseudo-unicode str. into font specific pseudo-UCS-4 str.
02651     if (aIsWide) {
02652 #ifdef IS_LITTLE_ENDIAN
02653         // Convert BE UTF-16 to LE UTF-16 for 'wide' custom fonts
02654         char* pstr = med;
02655         while (pstr < med + medLen) {
02656             PRUint8 tmp = pstr[0];
02657             pstr[0] = pstr[1];
02658             pstr[1] = tmp;
02659             pstr += 2; // swap every two bytes
02660         }
02661 #endif
02662         // Convert 16bit  custom font codes to UCS4
02663         ConvertUnicharToUCS4(NS_REINTERPRET_CAST(PRUnichar *, med),
02664                              medLen >> 1, aResult, &aDestLen);
02665         rv = aDestLen ? rv : NS_ERROR_OUT_OF_MEMORY;
02666     }
02667     else {
02668         // Convert 8bit custom font codes to UCS4
02669         ConvertCharToUCS4(med, medLen, aResult, &aDestLen);
02670         rv = aDestLen ? rv : NS_ERROR_OUT_OF_MEMORY;
02671     }
02672 
02673     return rv;
02674 }