Back to index

lightning-sunbird  0.9+nobinonly
nsFontMetricsWin.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:expandtab:shiftwidth=2:tabstop=2:
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
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   Roger B. Sidje <rbs@maths.uq.edu.au>
00026  *   Pierre Phaneuf <pp@ludusdesign.com>
00027  *   Jungshik Shin  <jshin@mailaps.org>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either of the GNU General Public License Version 2 or later (the "GPL"),
00031  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 #include "nsIPref.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsILanguageAtomService.h"
00046 #include "nsICharsetConverterManager.h"
00047 #include "nsICharRepresentable.h"
00048 #include "nsISaveAsCharset.h"
00049 #include "nsIObserver.h"
00050 #include "nsIObserverService.h"
00051 #include "nsFontMetricsWin.h"
00052 #include "nsQuickSort.h"
00053 #include "nsTextFormatter.h"
00054 #include "nsIFontPackageProxy.h"
00055 #include "nsIPersistentProperties2.h"
00056 #include "nsNetUtil.h"
00057 #include "prmem.h"
00058 #include "plhash.h"
00059 #include "prprf.h"
00060 #include "nsReadableUtils.h"
00061 #include "nsUnicodeRange.h"
00062 #include "nsAutoBuffer.h"
00063 
00064 #define DEFAULT_TTF_SYMBOL_ENCODING "windows-1252"
00065 #define IS_RTL_PRESENTATION_FORM(c) ((0xfb1d <= (c)) && ((c)<= 0xfefc))
00066 
00067 #define NOT_SETUP 0x33
00068 static PRBool gIsWIN95OR98 = NOT_SETUP;
00069 
00070 PRBool IsWin95OrWin98()
00071 {
00072 #ifndef WINCE
00073   if (NOT_SETUP == gIsWIN95OR98) {
00074     OSVERSIONINFO os;
00075     os.dwOSVersionInfoSize = sizeof(os);
00076     ::GetVersionEx(&os);
00077     // XXX This may need tweaking for win98
00078     if (VER_PLATFORM_WIN32_WINDOWS == os.dwPlatformId) {
00079       gIsWIN95OR98 = PR_TRUE;
00080     }
00081     else {
00082       gIsWIN95OR98 = PR_FALSE;
00083     }
00084   }
00085   return gIsWIN95OR98;
00086 #else
00087   return PR_TRUE;
00088 #endif
00089 }
00090 
00091 extern PRBool UseAFunctions();
00092 
00093 #undef USER_DEFINED
00094 #define USER_DEFINED "x-user-def"
00095 
00096 // Note: the replacement char must be a char that can be found in common unicode fonts
00097 #define NS_REPLACEMENT_CHAR  PRUnichar(0x003F) // question mark
00098 //#define NS_REPLACEMENT_CHAR  PRUnichar(0xFFFD) // Unicode's replacement char
00099 //#define NS_REPLACEMENT_CHAR  PRUnichar(0x2370) // Boxed question mark
00100 //#define NS_REPLACEMENT_CHAR  PRUnichar(0x00BF) // Inverted question mark
00101 //#define NS_REPLACEMENT_CHAR  PRUnichar(0x25AD) // White rectangle
00102 
00103 enum eCharset
00104 {
00105   eCharset_DEFAULT = 0,
00106   eCharset_ANSI,
00107   eCharset_EASTEUROPE,
00108   eCharset_RUSSIAN,
00109   eCharset_GREEK,
00110   eCharset_TURKISH,
00111   eCharset_HEBREW,
00112   eCharset_ARABIC,
00113   eCharset_BALTIC,
00114   eCharset_THAI,
00115   eCharset_SHIFTJIS,
00116   eCharset_GB2312,
00117   eCharset_HANGEUL,
00118   eCharset_CHINESEBIG5,
00119   eCharset_JOHAB,
00120   eCharset_COUNT
00121 };
00122 
00123 struct nsCharsetInfo
00124 {
00125   char*    mName;
00126   PRUint16 mCodePage;
00127   char*    mLangGroup;
00128   PRUint16* (*GenerateMap)(nsCharsetInfo* aSelf);
00129   PRUint16* mCCMap;
00130 };
00131 
00132 static PRUint16* GenerateDefault(nsCharsetInfo* aSelf);
00133 static PRUint16* GenerateSingleByte(nsCharsetInfo* aSelf);
00134 static PRUint16* GenerateMultiByte(nsCharsetInfo* aSelf);
00135 static PRBool    LookupWinFontName(const nsAFlatString& aName,
00136                                    nsAString& aWinName);
00137 
00138 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
00139 static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
00140 
00141 nsVoidArray* nsFontMetricsWin::gGlobalFonts = nsnull;
00142 PLHashTable* nsFontMetricsWin::gFontWeights = nsnull;
00143 PLHashTable* nsFontMetricsWin::gFontMaps = nsnull;
00144 PRUint16* nsFontMetricsWin::gEmptyCCMap = nsnull;
00145 
00146 #define NS_MAX_FONT_WEIGHT 900
00147 #define NS_MIN_FONT_WEIGHT 100
00148 
00149 
00150 static nsIPersistentProperties* gFontEncodingProperties = nsnull;
00151 static nsIPersistentProperties* gFontNameMapProperties = nsnull;
00152 static nsICharsetConverterManager* gCharsetManager = nsnull;
00153 static nsIUnicodeEncoder* gUserDefinedConverter = nsnull;
00154 static nsISaveAsCharset* gFontSubstituteConverter = nsnull;
00155 static nsIPref* gPref = nsnull;
00156 static nsIFontPackageProxy* gFontPackageProxy = nsnull;
00157 
00158 static nsIAtom* gUsersLocale = nsnull;
00159 static nsIAtom* gSystemLocale = nsnull;
00160 static nsIAtom* gUserDefined = nsnull;
00161 static nsIAtom* gJA = nsnull;
00162 static nsIAtom* gKO = nsnull;
00163 static nsIAtom* gZHTW = nsnull;
00164 static nsIAtom* gZHCN = nsnull;
00165 static nsIAtom* gZHHK = nsnull;
00166 
00167 static nsString* gCodepageStr = nsnull;
00168 
00169 static int gInitialized = 0;
00170 static PRBool gDoingLineheightFixup = PR_FALSE;
00171 static PRUint16* gUserDefinedCCMap = nsnull;
00172 
00173 // 'virtual' font to 'absorb' truly invisible characters (a subset of
00174 // default_ignorable_codepoints listed in 
00175 // http://www.unicode.org/Public/UNIDATA/DerivedCoreProperties.txt)
00176 // and turn them to  nothingness.
00177 static nsFontWin* gFontForIgnorable = nsnull;
00178 
00179 #include "ignorable.x-ccmap"
00180 DEFINE_X_CCMAP(gIgnorableCCMapExt, /* nothing */);
00181 
00182 static nsCharsetInfo gCharsetInfo[eCharset_COUNT] =
00183 {
00184   { "DEFAULT",     0,    "",               GenerateDefault,    nsnull},
00185   { "ANSI",        1252, "x-western",      GenerateSingleByte, nsnull},
00186   { "EASTEUROPE",  1250, "x-central-euro", GenerateSingleByte, nsnull},
00187   { "RUSSIAN",     1251, "x-cyrillic",     GenerateSingleByte, nsnull},
00188   { "GREEK",       1253, "el",             GenerateSingleByte, nsnull},
00189   { "TURKISH",     1254, "tr",             GenerateSingleByte, nsnull},
00190   { "HEBREW",      1255, "he",             GenerateSingleByte, nsnull},
00191   { "ARABIC",      1256, "ar",             GenerateSingleByte, nsnull},
00192   { "BALTIC",      1257, "x-baltic",       GenerateSingleByte, nsnull},
00193   { "THAI",        874,  "th",             GenerateSingleByte, nsnull},
00194   { "SHIFTJIS",    932,  "ja",             GenerateMultiByte,  nsnull},
00195   { "GB2312",      936,  "zh-CN",          GenerateMultiByte,  nsnull},
00196   { "HANGEUL",     949,  "ko",             GenerateMultiByte,  nsnull},
00197   { "CHINESEBIG5", 950,  "zh-TW",          GenerateMultiByte,  nsnull},
00198   { "JOHAB",       1361, "ko-XXX",         GenerateMultiByte,  nsnull}
00199 };
00200 
00201 static void
00202 FreeGlobals(void)
00203 {
00204   gInitialized = 0;
00205 
00206   NS_IF_RELEASE(gFontEncodingProperties);
00207   NS_IF_RELEASE(gFontNameMapProperties);
00208   NS_IF_RELEASE(gCharsetManager);
00209   NS_IF_RELEASE(gPref);
00210   NS_IF_RELEASE(gUsersLocale);
00211   NS_IF_RELEASE(gSystemLocale);
00212   NS_IF_RELEASE(gUserDefined);
00213   NS_IF_RELEASE(gUserDefinedConverter);
00214   NS_IF_RELEASE(gFontPackageProxy);
00215   if (gUserDefinedCCMap)
00216     FreeCCMap(gUserDefinedCCMap);
00217   NS_IF_RELEASE(gJA);
00218   NS_IF_RELEASE(gKO);
00219   NS_IF_RELEASE(gZHTW);
00220   NS_IF_RELEASE(gZHCN);
00221   NS_IF_RELEASE(gZHHK);
00222 
00223   // free CMap
00224   if (nsFontMetricsWin::gFontMaps) {
00225     PL_HashTableDestroy(nsFontMetricsWin::gFontMaps);
00226     nsFontMetricsWin::gFontMaps = nsnull;
00227     if (nsFontMetricsWin::gEmptyCCMap) {
00228       FreeCCMap(nsFontMetricsWin::gEmptyCCMap);
00229       nsFontMetricsWin::gEmptyCCMap = nsnull;
00230     }
00231   }
00232 
00233   if (nsFontMetricsWin::gGlobalFonts) {
00234     for (int i = nsFontMetricsWin::gGlobalFonts->Count()-1; i >= 0; --i) {
00235       nsGlobalFont* font = (nsGlobalFont*)nsFontMetricsWin::gGlobalFonts->ElementAt(i);
00236       delete font;
00237     }
00238     delete nsFontMetricsWin::gGlobalFonts;
00239     nsFontMetricsWin::gGlobalFonts = nsnull;
00240   }
00241 
00242   if (gFontForIgnorable) {
00243     delete gFontForIgnorable;
00244     gFontForIgnorable = nsnull;
00245   }
00246 
00247   if (gCodepageStr) {
00248     delete gCodepageStr;
00249     gCodepageStr = nsnull; 
00250   }
00251 
00252   // free Font weight
00253   if (nsFontMetricsWin::gFontWeights) {
00254     PL_HashTableDestroy(nsFontMetricsWin::gFontWeights);
00255     nsFontMetricsWin::gFontWeights = nsnull;
00256   }
00257 
00258   // free generated charset maps
00259   for (int i = 0; i < eCharset_COUNT; ++i) {
00260     if (gCharsetInfo[i].mCCMap) {
00261       FreeCCMap(gCharsetInfo[i].mCCMap);
00262       gCharsetInfo[i].mCCMap = nsnull;
00263     }
00264   }
00265 }
00266 
00267 class nsFontCleanupObserver : public nsIObserver {
00268 public:
00269   NS_DECL_ISUPPORTS
00270   NS_DECL_NSIOBSERVER
00271 
00272   nsFontCleanupObserver() { }
00273   virtual ~nsFontCleanupObserver() {}
00274 };
00275 
00276 NS_IMPL_ISUPPORTS1(nsFontCleanupObserver, nsIObserver)
00277 
00278 NS_IMETHODIMP nsFontCleanupObserver::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
00279 {
00280   if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
00281     FreeGlobals();
00282   }
00283   return NS_OK;
00284 }
00285 
00286 static nsFontCleanupObserver *gFontCleanupObserver;
00287 
00288 #undef CHAR_BUFFER_SIZE
00289 #define CHAR_BUFFER_SIZE 1024
00290 
00291 typedef nsAutoBuffer<char, CHAR_BUFFER_SIZE> nsAutoCharBuffer;
00292 typedef nsAutoBuffer<PRUnichar, CHAR_BUFFER_SIZE> nsAutoChar16Buffer;
00293 
00294 class nsFontSubset : public nsFontWin
00295 {
00296 public:
00297   nsFontSubset();
00298   virtual ~nsFontSubset();
00299 
00300   virtual PRInt32 GetWidth(HDC aDC, const PRUnichar* aString,
00301                            PRUint32 aLength);
00302   virtual void DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
00303                           const PRUnichar* aString, PRUint32 aLength);
00304 #ifdef MOZ_MATHML
00305   virtual nsresult
00306   GetBoundingMetrics(HDC                aDC, 
00307                      const PRUnichar*   aString,
00308                      PRUint32           aLength,
00309                      nsBoundingMetrics& aBoundingMetrics);
00310 #ifdef NS_DEBUG
00311   virtual void DumpFontInfo();
00312 #endif // NS_DEBUG
00313 #endif
00314 
00315   int Load(HDC aDC, nsFontMetricsWinA* aFontMetricsWin, nsFontWinA* aFont);
00316 
00317   // convert a Unicode string to ANSI within our codepage
00318   virtual void Convert(const PRUnichar* aString, PRUint32 aLength,
00319                        nsAutoCharBuffer& aResult, PRUint32* aResultLength);
00320 
00321   BYTE     mCharset;
00322   PRUint16 mCodePage;
00323 };
00324 
00325 class nsFontSubsetSubstitute : public nsFontSubset
00326 {
00327 public:
00328   nsFontSubsetSubstitute(PRBool aIsForIgnorable = FALSE);
00329   virtual ~nsFontSubsetSubstitute();
00330 
00331   virtual PRInt32 GetWidth(HDC aDC, const PRUnichar* aString, PRUint32 aLength);
00332   virtual void DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
00333                           const PRUnichar* aString, PRUint32 aLength);
00334 #ifdef MOZ_MATHML
00335   virtual nsresult
00336   GetBoundingMetrics(HDC                aDC,
00337                      const PRUnichar*   aString,
00338                      PRUint32           aLength,
00339                      nsBoundingMetrics& aBoundingMetrics);
00340 #ifdef NS_DEBUG
00341   virtual void DumpFontInfo();
00342 #endif // NS_DEBUG
00343 #endif
00344 
00345   // overloaded method to convert all chars to substitute chars
00346   virtual void Convert(const PRUnichar* aString, PRUint32 aLength,
00347                        nsAutoCharBuffer& aResult, PRUint32* aResultLength);
00348   //when fontSubstitute declares it supports a certain char, no need to check subset,
00349   // since we have one and only one subset.
00350   virtual PRBool HasGlyph(PRUnichar ch) {return PR_TRUE;};
00351 
00352 private:
00353   PRBool mIsForIgnorable;
00354 };
00355 
00356 static nsresult
00357 InitGlobals(void)
00358 {
00359   CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
00360   if (!gCharsetManager) {
00361     FreeGlobals();
00362     return NS_ERROR_FAILURE;
00363   }
00364   CallGetService(kPrefCID, &gPref);
00365   if (!gPref) {
00366     FreeGlobals();
00367     return NS_ERROR_FAILURE;
00368   }
00369 
00370   // if we do not include/compensate external leading in calculating normal 
00371   // line height, we don't set gDoingLineheightFixup either to keep old behavior.
00372   // These code should be eliminated in future when we choose to stay with 
00373   // one normal lineheight calculation method.
00374   PRInt32 intPref;
00375   if (NS_SUCCEEDED(gPref->GetIntPref(
00376       "browser.display.normal_lineheight_calc_control", &intPref)))
00377     gDoingLineheightFixup = (intPref != 0);
00378 
00379   nsCOMPtr<nsILanguageAtomService> langService;
00380   langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
00381   if (langService) {
00382     NS_IF_ADDREF(gUsersLocale = langService->GetLocaleLanguageGroup());
00383   }
00384   if (!gUsersLocale) {
00385     gUsersLocale = NS_NewAtom("x-western");
00386   }
00387   if (!gUsersLocale) {
00388     FreeGlobals();
00389     return NS_ERROR_OUT_OF_MEMORY;
00390   }
00391 
00392   // used in LookupWinFontName()
00393   if (!gCodepageStr) {
00394     gCodepageStr = new nsString(NS_LITERAL_STRING(".cp"));
00395   }
00396   if (!gCodepageStr) {
00397     FreeGlobals();
00398     return NS_ERROR_OUT_OF_MEMORY;
00399   }
00400 
00401   UINT cp = ::GetACP();
00402   gCodepageStr->AppendInt(cp); 
00403   
00404   if (!gSystemLocale) {
00405     for (int i = 1; i < eCharset_COUNT; ++i) {
00406       if (gCharsetInfo[i].mCodePage == cp) {
00407         gSystemLocale = NS_NewAtom(gCharsetInfo[i].mLangGroup);
00408         break;
00409       }
00410     }
00411   }
00412   if (!gSystemLocale) {
00413     gSystemLocale = gUsersLocale;
00414     NS_ADDREF(gSystemLocale);
00415   }
00416 
00417   gUserDefined = NS_NewAtom(USER_DEFINED);
00418   if (!gUserDefined) {
00419     FreeGlobals();
00420     return NS_ERROR_OUT_OF_MEMORY;
00421   }
00422   gJA = NS_NewAtom("ja");
00423   if (!gJA) {
00424     FreeGlobals();
00425     return NS_ERROR_OUT_OF_MEMORY;
00426   }
00427   gKO = NS_NewAtom("ko");
00428   if (!gKO) {
00429     FreeGlobals();
00430     return NS_ERROR_OUT_OF_MEMORY;
00431   }
00432   gZHCN = NS_NewAtom("zh-CN");
00433   if (!gZHCN) {
00434     FreeGlobals();
00435     return NS_ERROR_OUT_OF_MEMORY;
00436   }
00437   gZHTW = NS_NewAtom("zh-TW");
00438   if (!gZHTW) {
00439     FreeGlobals();
00440     return NS_ERROR_OUT_OF_MEMORY;
00441   }
00442   gZHHK = NS_NewAtom("zh-HK");
00443   if (!gZHHK) {
00444     FreeGlobals();
00445     return NS_ERROR_OUT_OF_MEMORY;
00446   }
00447 
00448   if (!UseAFunctions()) {
00449     gFontForIgnorable = new nsFontWinSubstitute(gIgnorableCCMapExt); 
00450     if (!gFontForIgnorable) {
00451       FreeGlobals();
00452       return NS_ERROR_OUT_OF_MEMORY;
00453     }
00454   } else {
00455     nsFontWinSubstituteA* font = new nsFontWinSubstituteA(gIgnorableCCMapExt);
00456     gFontForIgnorable = font;
00457     if (!gFontForIgnorable) {
00458       FreeGlobals();
00459       return NS_ERROR_OUT_OF_MEMORY;
00460     }
00461     font->mSubsets = (nsFontSubset**)nsMemory::Alloc(sizeof(nsFontSubset*));
00462     if (!font->mSubsets) {
00463       FreeGlobals();
00464       return NS_ERROR_OUT_OF_MEMORY;
00465     }
00466     font->mSubsets[0] = nsnull;
00467     nsFontSubsetSubstitute* subset = new nsFontSubsetSubstitute(TRUE);
00468     if (!subset) {
00469       FreeGlobals();
00470       return NS_ERROR_OUT_OF_MEMORY;
00471     }
00472     font->mSubsetsCount = 1;
00473     font->mSubsets[0] = subset;
00474   }
00475 
00476   //register an observer to take care of cleanup
00477   gFontCleanupObserver = new nsFontCleanupObserver();
00478   if (!gFontCleanupObserver) {
00479     FreeGlobals();
00480     return NS_ERROR_OUT_OF_MEMORY;
00481   }
00482 
00483   // register for shutdown
00484   nsresult rv;
00485   nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1", &rv));
00486   if (NS_SUCCEEDED(rv)) {
00487     rv = observerService->AddObserver(gFontCleanupObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
00488   }
00489   gInitialized = 1;
00490 
00491   return NS_OK;
00492 }
00493 
00494 static void CheckFontLangGroup(nsIAtom* lang1, nsIAtom* lang2, const char* lang3)
00495 {
00496   if (lang1 == lang2) {
00497     nsresult res = NS_OK;
00498     if (!gFontPackageProxy) {
00499       res = CallGetService("@mozilla.org/intl/fontpackageservice;1",
00500                            &gFontPackageProxy);
00501       if (NS_FAILED(res)) {
00502         NS_ERROR("Cannot get the font package proxy");
00503         return;
00504       }
00505     }
00506 
00507     char fontpackageid[256];
00508     PR_snprintf(fontpackageid, sizeof(fontpackageid), "lang:%s", lang3);
00509     res = gFontPackageProxy->NeedFontPackage(fontpackageid);
00510     NS_ASSERTION(NS_SUCCEEDED(res), "cannot notify missing font package ");
00511   }
00512 }
00513 
00514 nsFontMetricsWin::nsFontMetricsWin()
00515 {
00516 }
00517   
00518 nsFontMetricsWin::~nsFontMetricsWin()
00519 {
00520   mSubstituteFont = nsnull; // released below
00521   mFontHandle = nsnull; // released below
00522 
00523   // mLoadedFont[0] is gFontForIgnorable that will be deleted in FreeGlobal
00524   for (PRInt32 i = mLoadedFonts.Count()-1; i > 0; --i) {
00525     delete (nsFontWin*)mLoadedFonts[i];
00526   }
00527   mLoadedFonts.Clear();
00528 
00529   if (mDeviceContext) {
00530     // Notify our device context that owns us so that it can update its font cache
00531     mDeviceContext->FontMetricsDeleted(this);
00532     mDeviceContext = nsnull;
00533   }
00534 }
00535 
00536 #ifdef LEAK_DEBUG
00537 nsrefcnt
00538 nsFontMetricsWin::AddRef()
00539 {
00540   NS_PRECONDITION(mRefCnt != 0, "resurrecting a dead object");
00541   return ++mRefCnt;
00542 }
00543 
00544 nsrefcnt
00545 nsFontMetricsWin::Release()
00546 {
00547   NS_PRECONDITION(mRefCnt != 0, "too many release's");
00548   if (--mRefCnt == 0) {
00549     delete this;
00550   }
00551   return mRefCnt;
00552 }
00553 
00554 NS_IMPL_QUERY_INTERFACE1(nsFontMetricsWin, nsIFontMetrics)
00555   
00556 #else
00557 NS_IMPL_ISUPPORTS1(nsFontMetricsWin, nsIFontMetrics)
00558 #endif
00559 
00560 NS_IMETHODIMP
00561 nsFontMetricsWin::Init(const nsFont& aFont, nsIAtom* aLangGroup,
00562   nsIDeviceContext *aContext)
00563 {
00564   nsresult res;
00565   if (!gInitialized) {
00566     res = InitGlobals();
00567     //XXXrbs this should be a fatal startup error
00568     NS_ASSERTION(NS_SUCCEEDED(res), "No font at all has been created");
00569     if (NS_FAILED(res)) {
00570       return res;
00571     }
00572   }
00573 
00574   mFont = aFont;
00575   mLangGroup = aLangGroup;
00576 
00577   // do special checking for the following lang group
00578   // * use fonts?
00579   PRInt32 useDccFonts = 0;
00580   if (NS_SUCCEEDED(gPref->GetIntPref("browser.display.use_document_fonts", &useDccFonts)) && (useDccFonts != 0)) {
00581     CheckFontLangGroup(mLangGroup, gJA,   "ja");
00582     CheckFontLangGroup(mLangGroup, gKO,   "ko");
00583     CheckFontLangGroup(mLangGroup, gZHTW, "zh-TW");
00584     CheckFontLangGroup(mLangGroup, gZHCN, "zh-CN");
00585     CheckFontLangGroup(mLangGroup, gZHHK, "zh-HK");
00586   }
00587 
00588   //don't addref this to avoid circular refs
00589   mDeviceContext = (nsDeviceContextWin *)aContext;
00590   return RealizeFont();
00591 }
00592 
00593 NS_IMETHODIMP
00594 nsFontMetricsWin::Destroy()
00595 {
00596   mDeviceContext = nsnull;
00597   return NS_OK;
00598 }
00599 
00600 // The following flag is not defined by MS in the vc include files
00601 // This flag is documented in the following document
00602 // HOWTO: Display Graphic Chars on Chinese & Korean Windows (Q171153)
00603 // http://support.microsoft.com/?kbid=171153
00604 // According to the document, this flag will only impact Korean and
00605 // Chinese window
00606 #define CLIP_TURNOFF_FONTASSOCIATION 0x40
00607 
00608 void
00609 nsFontMetricsWin::FillLogFont(LOGFONT* logFont, PRInt32 aWeight,
00610   PRBool aSizeOnly)
00611 {
00612   float app2dev;
00613   app2dev = mDeviceContext->AppUnitsToDevUnits();
00614   logFont->lfHeight = - NSToIntRound(mFont.size * app2dev);
00615 
00616   if (logFont->lfHeight == 0) {
00617     logFont->lfHeight = -1;
00618   }
00619 
00620   // Quick return if we came here just to compute the font size
00621   if (aSizeOnly) return;
00622 
00623   // Fill in logFont structure
00624   logFont->lfWidth          = 0; 
00625   logFont->lfEscapement     = 0;
00626   logFont->lfOrientation    = 0;
00627   logFont->lfUnderline      =
00628     (mFont.decorations & NS_FONT_DECORATION_UNDERLINE)
00629     ? TRUE : FALSE;
00630   logFont->lfStrikeOut      =
00631     (mFont.decorations & NS_FONT_DECORATION_LINE_THROUGH)
00632     ? TRUE : FALSE;
00633 #ifndef WINCE
00634   logFont->lfCharSet        = mIsUserDefined ? ANSI_CHARSET : DEFAULT_CHARSET;
00635   logFont->lfOutPrecision   = OUT_TT_PRECIS;
00636   logFont->lfClipPrecision  = CLIP_TURNOFF_FONTASSOCIATION;
00637 #else
00638   logFont->lfCharSet        = DEFAULT_CHARSET;
00639   logFont->lfOutPrecision   = OUT_DEFAULT_PRECIS;
00640   logFont->lfClipPrecision  = CLIP_DEFAULT_PRECIS;
00641 #endif
00642   logFont->lfQuality        = DEFAULT_QUALITY;
00643   logFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
00644   logFont->lfWeight = aWeight;
00645   logFont->lfItalic = (mFont.style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE))
00646     ? TRUE : FALSE;   // XXX need better oblique support
00647 
00648 #ifdef NS_DEBUG
00649   // Make Purify happy
00650   memset(logFont->lfFaceName, 0, sizeof(logFont->lfFaceName));
00651 #endif
00652 }
00653 
00654 #undef CFF
00655 #define CFF  (('C') | ('F' << 8) | ('F' << 16) | (' ' << 24))
00656 #undef CMAP
00657 #define CMAP (('c') | ('m' << 8) | ('a' << 16) | ('p' << 24))
00658 #undef HEAD
00659 #define HEAD (('h') | ('e' << 8) | ('a' << 16) | ('d' << 24))
00660 #undef LOCA
00661 #define LOCA (('l') | ('o' << 8) | ('c' << 16) | ('a' << 24))
00662 #undef NAME
00663 #define NAME (('n') | ('a' << 8) | ('m' << 16) | ('e' << 24))
00664 
00665 #ifdef IS_BIG_ENDIAN 
00666 # undef GET_SHORT
00667 # define GET_SHORT(p) (*((PRUint16*)p))
00668 # undef GET_LONG
00669 # define GET_LONG(p)  (*((PRUint32*)p))
00670 #else
00671 # ifdef IS_LITTLE_ENDIAN 
00672 #  undef GET_SHORT
00673 #  define GET_SHORT(p) (((p)[0] << 8) | (p)[1])
00674 #  undef GET_LONG
00675 #  define GET_LONG(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3])
00676 # endif
00677 #endif
00678 
00679 
00680 #define AUTO_FONTDATA_BUFFER_SIZE 16384 /* 16K */
00681 
00682 typedef nsAutoBuffer<PRUint8, AUTO_FONTDATA_BUFFER_SIZE> nsAutoFontDataBuffer;
00683 
00684 static PRUint16
00685 GetGlyphIndex(PRUint16 segCount, PRUint16* endCode, PRUint16* startCode,
00686   PRUint16* idRangeOffset, PRUint16* idDelta, PRUint8* end, PRUint16 aChar)
00687 {
00688   PRUint16 glyphIndex = 0;
00689   PRUint16 i;
00690   for (i = 0; i < segCount; ++i) {
00691     if (endCode[i] >= aChar) {
00692       break;
00693     }
00694   }
00695   PRUint16 startC = startCode[i];
00696   if (startC <= aChar) {
00697     if (idRangeOffset[i]) {
00698       PRUint16* p =
00699         (idRangeOffset[i]/2 + (aChar - startC) + &idRangeOffset[i]);
00700       if ((PRUint8*) p < end) {
00701         if (*p) {
00702           glyphIndex = (idDelta[i] + *p) % 65536;
00703         }
00704       }
00705     }
00706     else {
00707       glyphIndex = (idDelta[i] + aChar) % 65536;
00708     }
00709   }
00710 
00711   return glyphIndex;
00712 }
00713 
00714 enum eGetNameError
00715 {
00716   eGetName_OK = 0,    // exit code for a TrueType font
00717   eGetName_GDIError,  // we use this internally to flag a raster (bitmap) font
00718   eGetName_OtherError // unknown error, the font can't be used
00719 };
00720 
00721 static eGetNameError
00722 GetNAME(HDC aDC, nsString* aName, PRBool* aIsSymbolEncoding = nsnull)
00723 {
00724 #ifdef WINCE
00725   return eGetName_GDIError;
00726 #else
00727 
00728   DWORD len = GetFontData(aDC, NAME, 0, nsnull, 0);
00729   if (len == GDI_ERROR) {
00730     TEXTMETRIC metrics;
00731     if (::GetTextMetrics(aDC, &metrics) == 0) // can fail here -- see bug 113779#c81
00732       return eGetName_OtherError;
00733     return (metrics.tmPitchAndFamily & TMPF_TRUETYPE) ?
00734       eGetName_OtherError : eGetName_GDIError;
00735   }
00736   if (!len) {
00737     return eGetName_OtherError;
00738   }
00739   nsAutoFontDataBuffer buffer;
00740   if (!buffer.EnsureElemCapacity(len)) {
00741     return eGetName_OtherError;
00742   }
00743   PRUint8* buf = buffer.get();
00744 
00745   DWORD newLen = GetFontData(aDC, NAME, 0, buf, len);
00746   if (newLen != len) {
00747     return eGetName_OtherError;
00748   }
00749   PRUint8* p = buf + 2;
00750   PRUint16 n = GET_SHORT(p);
00751   p += 2;
00752   PRUint16 offset = GET_SHORT(p);
00753   p += 2;
00754   PRUint16 i;
00755   PRUint16 idLength;
00756   PRUint16 idOffset;
00757   for (i = 0; i < n; ++i) {
00758     PRUint16 platform = GET_SHORT(p);
00759     p += 2;
00760     PRUint16 encoding = GET_SHORT(p);
00761     p += 4;
00762     PRUint16 name = GET_SHORT(p);
00763     p += 2;
00764     idLength = GET_SHORT(p);
00765     p += 2;
00766     idOffset = GET_SHORT(p);
00767     p += 2;
00768     // encoding: 1 == Unicode; 0 == symbol
00769     if ((platform == 3) && ((encoding == 1) || (!encoding)) && (name == 3)) {
00770       if (aIsSymbolEncoding) {
00771         *aIsSymbolEncoding = encoding == 0;
00772       }
00773       break;
00774     }
00775   }
00776   if (i == n) {
00777     return eGetName_OtherError;
00778   }
00779   p = buf + offset + idOffset;
00780   idLength /= 2;
00781   // Prefix with a little flag to distinguish quirky fonts. Assume
00782   // '0' (i.e., non quirks) to begin with. On return, the caller can
00783   // decide to treat this font in quirks fashion and override with
00784   // aName[0] = '1'. More info in bug 195038.
00785   PRUnichar c = '0';
00786   aName->Append(c);
00787   for (i = 0; i < idLength; ++i) {
00788     c = GET_SHORT(p);
00789     p += 2;
00790     aName->Append(c);
00791   }
00792 
00793   return eGetName_OK;
00794 #endif
00795 }
00796 
00797 static PLHashNumber
00798 HashKey(const void* aString)
00799 {
00800   const nsString* str = (const nsString*)aString;
00801   return (PLHashNumber)
00802     nsCRT::HashCode(str->get());
00803 }
00804 
00805 static PRIntn
00806 CompareKeys(const void* aStr1, const void* aStr2)
00807 {
00808   return nsCRT::strcmp(((const nsString*) aStr1)->get(),
00809     ((const nsString*) aStr2)->get()) == 0;
00810 }
00811 
00812 static int
00813 GetIndexToLocFormat(HDC aDC)
00814 {
00815   PRUint16 indexToLocFormat;
00816   if (GetFontData(aDC, HEAD, 50, &indexToLocFormat, 2) != 2) {
00817     return -1;
00818   }
00819   if (!indexToLocFormat) {
00820     return 0;
00821   }
00822   return 1;
00823 }
00824 
00825 static nsresult
00826 GetSpaces(HDC aDC, PRBool* aIsCFFOutline, PRUint32* aMaxGlyph,
00827   nsAutoFontDataBuffer& aIsSpace)
00828 {
00829   // OpenType fonts with CFF outline do not have the 'loca' table
00830   DWORD len = GetFontData(aDC, CFF, 0, nsnull, 0);
00831   if ((len != GDI_ERROR) && len) {
00832     *aIsCFFOutline = PR_TRUE;
00833     return NS_OK;
00834   }
00835   *aIsCFFOutline = PR_FALSE;
00836   int isLong = GetIndexToLocFormat(aDC);
00837   if (isLong < 0) {
00838     return NS_ERROR_FAILURE;
00839   }
00840   len = GetFontData(aDC, LOCA, 0, nsnull, 0);
00841   if ((len == GDI_ERROR) || (!len)) {
00842     return NS_ERROR_FAILURE;
00843   }
00844   if (!aIsSpace.EnsureElemCapacity(len)) {
00845     return NS_ERROR_OUT_OF_MEMORY;
00846   }
00847   PRUint8* buf = aIsSpace.get();
00848   DWORD newLen = GetFontData(aDC, LOCA, 0, buf, len);
00849   if (newLen != len) {
00850     return NS_ERROR_FAILURE;
00851   }
00852   if (isLong) {
00853     DWORD longLen = ((len / 4) - 1);
00854     *aMaxGlyph = longLen;
00855     PRUint32* longBuf = (PRUint32*) buf;
00856     for (PRUint32 i = 0; i < longLen; ++i) {
00857       if (longBuf[i] == longBuf[i+1]) {
00858         buf[i] = 1;
00859       }
00860       else {
00861         buf[i] = 0;
00862       }
00863     }
00864   }
00865   else {
00866     DWORD shortLen = ((len / 2) - 1);
00867     *aMaxGlyph = shortLen;
00868     PRUint16* shortBuf = (PRUint16*) buf;
00869     for (PRUint16 i = 0; i < shortLen; ++i) {
00870       if (shortBuf[i] == shortBuf[i+1]) {
00871         buf[i] = 1;
00872       }
00873       else {
00874         buf[i] = 0;
00875       }
00876     }
00877   }
00878 
00879   return NS_OK;
00880 }
00881 
00882 // The following is a workaround for a Japanese Windows 95 problem.
00883 
00884 static PRUint8 gBitToCharset[64] =
00885 {
00886 /*00*/ ANSI_CHARSET,
00887 /*01*/ EASTEUROPE_CHARSET,
00888 /*02*/ RUSSIAN_CHARSET,
00889 /*03*/ GREEK_CHARSET,
00890 /*04*/ TURKISH_CHARSET,
00891 /*05*/ HEBREW_CHARSET,
00892 /*06*/ ARABIC_CHARSET,
00893 /*07*/ BALTIC_CHARSET,
00894 /*08*/ DEFAULT_CHARSET,
00895 /*09*/ DEFAULT_CHARSET,
00896 /*10*/ DEFAULT_CHARSET,
00897 /*11*/ DEFAULT_CHARSET,
00898 /*12*/ DEFAULT_CHARSET,
00899 /*13*/ DEFAULT_CHARSET,
00900 /*14*/ DEFAULT_CHARSET,
00901 /*15*/ DEFAULT_CHARSET,
00902 /*16*/ THAI_CHARSET,
00903 /*17*/ SHIFTJIS_CHARSET,
00904 /*18*/ GB2312_CHARSET,
00905 /*19*/ HANGEUL_CHARSET,
00906 /*20*/ CHINESEBIG5_CHARSET,
00907 /*21*/ JOHAB_CHARSET,
00908 /*22*/ DEFAULT_CHARSET,
00909 /*23*/ DEFAULT_CHARSET,
00910 /*24*/ DEFAULT_CHARSET,
00911 /*25*/ DEFAULT_CHARSET,
00912 /*26*/ DEFAULT_CHARSET,
00913 /*27*/ DEFAULT_CHARSET,
00914 /*28*/ DEFAULT_CHARSET,
00915 /*29*/ DEFAULT_CHARSET,
00916 /*30*/ DEFAULT_CHARSET,
00917 /*31*/ DEFAULT_CHARSET,
00918 /*32*/ DEFAULT_CHARSET,
00919 /*33*/ DEFAULT_CHARSET,
00920 /*34*/ DEFAULT_CHARSET,
00921 /*35*/ DEFAULT_CHARSET,
00922 /*36*/ DEFAULT_CHARSET,
00923 /*37*/ DEFAULT_CHARSET,
00924 /*38*/ DEFAULT_CHARSET,
00925 /*39*/ DEFAULT_CHARSET,
00926 /*40*/ DEFAULT_CHARSET,
00927 /*41*/ DEFAULT_CHARSET,
00928 /*42*/ DEFAULT_CHARSET,
00929 /*43*/ DEFAULT_CHARSET,
00930 /*44*/ DEFAULT_CHARSET,
00931 /*45*/ DEFAULT_CHARSET,
00932 /*46*/ DEFAULT_CHARSET,
00933 /*47*/ DEFAULT_CHARSET,
00934 /*48*/ DEFAULT_CHARSET,
00935 /*49*/ DEFAULT_CHARSET,
00936 /*50*/ DEFAULT_CHARSET,
00937 /*51*/ DEFAULT_CHARSET,
00938 /*52*/ DEFAULT_CHARSET,
00939 /*53*/ DEFAULT_CHARSET,
00940 /*54*/ DEFAULT_CHARSET,
00941 /*55*/ DEFAULT_CHARSET,
00942 /*56*/ DEFAULT_CHARSET,
00943 /*57*/ DEFAULT_CHARSET,
00944 /*58*/ DEFAULT_CHARSET,
00945 /*59*/ DEFAULT_CHARSET,
00946 /*60*/ DEFAULT_CHARSET,
00947 /*61*/ DEFAULT_CHARSET,
00948 /*62*/ DEFAULT_CHARSET,
00949 /*63*/ DEFAULT_CHARSET
00950 };
00951 
00952 static eCharset gCharsetToIndex[256] =
00953 {
00954   /* 000 */ eCharset_ANSI,
00955   /* 001 */ eCharset_DEFAULT,
00956   /* 002 */ eCharset_DEFAULT, // SYMBOL
00957   /* 003 */ eCharset_DEFAULT,
00958   /* 004 */ eCharset_DEFAULT,
00959   /* 005 */ eCharset_DEFAULT,
00960   /* 006 */ eCharset_DEFAULT,
00961   /* 007 */ eCharset_DEFAULT,
00962   /* 008 */ eCharset_DEFAULT,
00963   /* 009 */ eCharset_DEFAULT,
00964   /* 010 */ eCharset_DEFAULT,
00965   /* 011 */ eCharset_DEFAULT,
00966   /* 012 */ eCharset_DEFAULT,
00967   /* 013 */ eCharset_DEFAULT,
00968   /* 014 */ eCharset_DEFAULT,
00969   /* 015 */ eCharset_DEFAULT,
00970   /* 016 */ eCharset_DEFAULT,
00971   /* 017 */ eCharset_DEFAULT,
00972   /* 018 */ eCharset_DEFAULT,
00973   /* 019 */ eCharset_DEFAULT,
00974   /* 020 */ eCharset_DEFAULT,
00975   /* 021 */ eCharset_DEFAULT,
00976   /* 022 */ eCharset_DEFAULT,
00977   /* 023 */ eCharset_DEFAULT,
00978   /* 024 */ eCharset_DEFAULT,
00979   /* 025 */ eCharset_DEFAULT,
00980   /* 026 */ eCharset_DEFAULT,
00981   /* 027 */ eCharset_DEFAULT,
00982   /* 028 */ eCharset_DEFAULT,
00983   /* 029 */ eCharset_DEFAULT,
00984   /* 030 */ eCharset_DEFAULT,
00985   /* 031 */ eCharset_DEFAULT,
00986   /* 032 */ eCharset_DEFAULT,
00987   /* 033 */ eCharset_DEFAULT,
00988   /* 034 */ eCharset_DEFAULT,
00989   /* 035 */ eCharset_DEFAULT,
00990   /* 036 */ eCharset_DEFAULT,
00991   /* 037 */ eCharset_DEFAULT,
00992   /* 038 */ eCharset_DEFAULT,
00993   /* 039 */ eCharset_DEFAULT,
00994   /* 040 */ eCharset_DEFAULT,
00995   /* 041 */ eCharset_DEFAULT,
00996   /* 042 */ eCharset_DEFAULT,
00997   /* 043 */ eCharset_DEFAULT,
00998   /* 044 */ eCharset_DEFAULT,
00999   /* 045 */ eCharset_DEFAULT,
01000   /* 046 */ eCharset_DEFAULT,
01001   /* 047 */ eCharset_DEFAULT,
01002   /* 048 */ eCharset_DEFAULT,
01003   /* 049 */ eCharset_DEFAULT,
01004   /* 050 */ eCharset_DEFAULT,
01005   /* 051 */ eCharset_DEFAULT,
01006   /* 052 */ eCharset_DEFAULT,
01007   /* 053 */ eCharset_DEFAULT,
01008   /* 054 */ eCharset_DEFAULT,
01009   /* 055 */ eCharset_DEFAULT,
01010   /* 056 */ eCharset_DEFAULT,
01011   /* 057 */ eCharset_DEFAULT,
01012   /* 058 */ eCharset_DEFAULT,
01013   /* 059 */ eCharset_DEFAULT,
01014   /* 060 */ eCharset_DEFAULT,
01015   /* 061 */ eCharset_DEFAULT,
01016   /* 062 */ eCharset_DEFAULT,
01017   /* 063 */ eCharset_DEFAULT,
01018   /* 064 */ eCharset_DEFAULT,
01019   /* 065 */ eCharset_DEFAULT,
01020   /* 066 */ eCharset_DEFAULT,
01021   /* 067 */ eCharset_DEFAULT,
01022   /* 068 */ eCharset_DEFAULT,
01023   /* 069 */ eCharset_DEFAULT,
01024   /* 070 */ eCharset_DEFAULT,
01025   /* 071 */ eCharset_DEFAULT,
01026   /* 072 */ eCharset_DEFAULT,
01027   /* 073 */ eCharset_DEFAULT,
01028   /* 074 */ eCharset_DEFAULT,
01029   /* 075 */ eCharset_DEFAULT,
01030   /* 076 */ eCharset_DEFAULT,
01031   /* 077 */ eCharset_DEFAULT, // MAC
01032   /* 078 */ eCharset_DEFAULT,
01033   /* 079 */ eCharset_DEFAULT,
01034   /* 080 */ eCharset_DEFAULT,
01035   /* 081 */ eCharset_DEFAULT,
01036   /* 082 */ eCharset_DEFAULT,
01037   /* 083 */ eCharset_DEFAULT,
01038   /* 084 */ eCharset_DEFAULT,
01039   /* 085 */ eCharset_DEFAULT,
01040   /* 086 */ eCharset_DEFAULT,
01041   /* 087 */ eCharset_DEFAULT,
01042   /* 088 */ eCharset_DEFAULT,
01043   /* 089 */ eCharset_DEFAULT,
01044   /* 090 */ eCharset_DEFAULT,
01045   /* 091 */ eCharset_DEFAULT,
01046   /* 092 */ eCharset_DEFAULT,
01047   /* 093 */ eCharset_DEFAULT,
01048   /* 094 */ eCharset_DEFAULT,
01049   /* 095 */ eCharset_DEFAULT,
01050   /* 096 */ eCharset_DEFAULT,
01051   /* 097 */ eCharset_DEFAULT,
01052   /* 098 */ eCharset_DEFAULT,
01053   /* 099 */ eCharset_DEFAULT,
01054   /* 100 */ eCharset_DEFAULT,
01055   /* 101 */ eCharset_DEFAULT,
01056   /* 102 */ eCharset_DEFAULT,
01057   /* 103 */ eCharset_DEFAULT,
01058   /* 104 */ eCharset_DEFAULT,
01059   /* 105 */ eCharset_DEFAULT,
01060   /* 106 */ eCharset_DEFAULT,
01061   /* 107 */ eCharset_DEFAULT,
01062   /* 108 */ eCharset_DEFAULT,
01063   /* 109 */ eCharset_DEFAULT,
01064   /* 110 */ eCharset_DEFAULT,
01065   /* 111 */ eCharset_DEFAULT,
01066   /* 112 */ eCharset_DEFAULT,
01067   /* 113 */ eCharset_DEFAULT,
01068   /* 114 */ eCharset_DEFAULT,
01069   /* 115 */ eCharset_DEFAULT,
01070   /* 116 */ eCharset_DEFAULT,
01071   /* 117 */ eCharset_DEFAULT,
01072   /* 118 */ eCharset_DEFAULT,
01073   /* 119 */ eCharset_DEFAULT,
01074   /* 120 */ eCharset_DEFAULT,
01075   /* 121 */ eCharset_DEFAULT,
01076   /* 122 */ eCharset_DEFAULT,
01077   /* 123 */ eCharset_DEFAULT,
01078   /* 124 */ eCharset_DEFAULT,
01079   /* 125 */ eCharset_DEFAULT,
01080   /* 126 */ eCharset_DEFAULT,
01081   /* 127 */ eCharset_DEFAULT,
01082   /* 128 */ eCharset_SHIFTJIS,
01083   /* 129 */ eCharset_HANGEUL,
01084   /* 130 */ eCharset_JOHAB,
01085   /* 131 */ eCharset_DEFAULT,
01086   /* 132 */ eCharset_DEFAULT,
01087   /* 133 */ eCharset_DEFAULT,
01088   /* 134 */ eCharset_GB2312,
01089   /* 135 */ eCharset_DEFAULT,
01090   /* 136 */ eCharset_CHINESEBIG5,
01091   /* 137 */ eCharset_DEFAULT,
01092   /* 138 */ eCharset_DEFAULT,
01093   /* 139 */ eCharset_DEFAULT,
01094   /* 140 */ eCharset_DEFAULT,
01095   /* 141 */ eCharset_DEFAULT,
01096   /* 142 */ eCharset_DEFAULT,
01097   /* 143 */ eCharset_DEFAULT,
01098   /* 144 */ eCharset_DEFAULT,
01099   /* 145 */ eCharset_DEFAULT,
01100   /* 146 */ eCharset_DEFAULT,
01101   /* 147 */ eCharset_DEFAULT,
01102   /* 148 */ eCharset_DEFAULT,
01103   /* 149 */ eCharset_DEFAULT,
01104   /* 150 */ eCharset_DEFAULT,
01105   /* 151 */ eCharset_DEFAULT,
01106   /* 152 */ eCharset_DEFAULT,
01107   /* 153 */ eCharset_DEFAULT,
01108   /* 154 */ eCharset_DEFAULT,
01109   /* 155 */ eCharset_DEFAULT,
01110   /* 156 */ eCharset_DEFAULT,
01111   /* 157 */ eCharset_DEFAULT,
01112   /* 158 */ eCharset_DEFAULT,
01113   /* 159 */ eCharset_DEFAULT,
01114   /* 160 */ eCharset_DEFAULT,
01115   /* 161 */ eCharset_GREEK,
01116   /* 162 */ eCharset_TURKISH,
01117   /* 163 */ eCharset_DEFAULT, // VIETNAMESE
01118   /* 164 */ eCharset_DEFAULT,
01119   /* 165 */ eCharset_DEFAULT,
01120   /* 166 */ eCharset_DEFAULT,
01121   /* 167 */ eCharset_DEFAULT,
01122   /* 168 */ eCharset_DEFAULT,
01123   /* 169 */ eCharset_DEFAULT,
01124   /* 170 */ eCharset_DEFAULT,
01125   /* 171 */ eCharset_DEFAULT,
01126   /* 172 */ eCharset_DEFAULT,
01127   /* 173 */ eCharset_DEFAULT,
01128   /* 174 */ eCharset_DEFAULT,
01129   /* 175 */ eCharset_DEFAULT,
01130   /* 176 */ eCharset_DEFAULT,
01131   /* 177 */ eCharset_HEBREW,
01132   /* 178 */ eCharset_ARABIC,
01133   /* 179 */ eCharset_DEFAULT,
01134   /* 180 */ eCharset_DEFAULT,
01135   /* 181 */ eCharset_DEFAULT,
01136   /* 182 */ eCharset_DEFAULT,
01137   /* 183 */ eCharset_DEFAULT,
01138   /* 184 */ eCharset_DEFAULT,
01139   /* 185 */ eCharset_DEFAULT,
01140   /* 186 */ eCharset_BALTIC,
01141   /* 187 */ eCharset_DEFAULT,
01142   /* 188 */ eCharset_DEFAULT,
01143   /* 189 */ eCharset_DEFAULT,
01144   /* 190 */ eCharset_DEFAULT,
01145   /* 191 */ eCharset_DEFAULT,
01146   /* 192 */ eCharset_DEFAULT,
01147   /* 193 */ eCharset_DEFAULT,
01148   /* 194 */ eCharset_DEFAULT,
01149   /* 195 */ eCharset_DEFAULT,
01150   /* 196 */ eCharset_DEFAULT,
01151   /* 197 */ eCharset_DEFAULT,
01152   /* 198 */ eCharset_DEFAULT,
01153   /* 199 */ eCharset_DEFAULT,
01154   /* 200 */ eCharset_DEFAULT,
01155   /* 201 */ eCharset_DEFAULT,
01156   /* 202 */ eCharset_DEFAULT,
01157   /* 203 */ eCharset_DEFAULT,
01158   /* 204 */ eCharset_RUSSIAN,
01159   /* 205 */ eCharset_DEFAULT,
01160   /* 206 */ eCharset_DEFAULT,
01161   /* 207 */ eCharset_DEFAULT,
01162   /* 208 */ eCharset_DEFAULT,
01163   /* 209 */ eCharset_DEFAULT,
01164   /* 210 */ eCharset_DEFAULT,
01165   /* 211 */ eCharset_DEFAULT,
01166   /* 212 */ eCharset_DEFAULT,
01167   /* 213 */ eCharset_DEFAULT,
01168   /* 214 */ eCharset_DEFAULT,
01169   /* 215 */ eCharset_DEFAULT,
01170   /* 216 */ eCharset_DEFAULT,
01171   /* 217 */ eCharset_DEFAULT,
01172   /* 218 */ eCharset_DEFAULT,
01173   /* 219 */ eCharset_DEFAULT,
01174   /* 220 */ eCharset_DEFAULT,
01175   /* 221 */ eCharset_DEFAULT,
01176   /* 222 */ eCharset_THAI,
01177   /* 223 */ eCharset_DEFAULT,
01178   /* 224 */ eCharset_DEFAULT,
01179   /* 225 */ eCharset_DEFAULT,
01180   /* 226 */ eCharset_DEFAULT,
01181   /* 227 */ eCharset_DEFAULT,
01182   /* 228 */ eCharset_DEFAULT,
01183   /* 229 */ eCharset_DEFAULT,
01184   /* 230 */ eCharset_DEFAULT,
01185   /* 231 */ eCharset_DEFAULT,
01186   /* 232 */ eCharset_DEFAULT,
01187   /* 233 */ eCharset_DEFAULT,
01188   /* 234 */ eCharset_DEFAULT,
01189   /* 235 */ eCharset_DEFAULT,
01190   /* 236 */ eCharset_DEFAULT,
01191   /* 237 */ eCharset_DEFAULT,
01192   /* 238 */ eCharset_EASTEUROPE,
01193   /* 239 */ eCharset_DEFAULT,
01194   /* 240 */ eCharset_DEFAULT,
01195   /* 241 */ eCharset_DEFAULT,
01196   /* 242 */ eCharset_DEFAULT,
01197   /* 243 */ eCharset_DEFAULT,
01198   /* 244 */ eCharset_DEFAULT,
01199   /* 245 */ eCharset_DEFAULT,
01200   /* 246 */ eCharset_DEFAULT,
01201   /* 247 */ eCharset_DEFAULT,
01202   /* 248 */ eCharset_DEFAULT,
01203   /* 249 */ eCharset_DEFAULT,
01204   /* 250 */ eCharset_DEFAULT,
01205   /* 251 */ eCharset_DEFAULT,
01206   /* 252 */ eCharset_DEFAULT,
01207   /* 253 */ eCharset_DEFAULT,
01208   /* 254 */ eCharset_DEFAULT,
01209   /* 255 */ eCharset_DEFAULT  // OEM
01210 };
01211 
01212 static PRUint8 gCharsetToBit[eCharset_COUNT] =
01213 {
01214        -1,  // DEFAULT
01215         0,  // ANSI_CHARSET,
01216         1,  // EASTEUROPE_CHARSET,
01217         2,  // RUSSIAN_CHARSET,
01218         3,  // GREEK_CHARSET,
01219         4,  // TURKISH_CHARSET,
01220         5,  // HEBREW_CHARSET,
01221         6,  // ARABIC_CHARSET,
01222         7,  // BALTIC_CHARSET,
01223        16,  // THAI_CHARSET,
01224        17,  // SHIFTJIS_CHARSET,
01225        18,  // GB2312_CHARSET,
01226        19,  // HANGEUL_CHARSET,
01227        20,  // CHINESEBIG5_CHARSET,
01228        21   // JOHAB_CHARSET,
01229 };
01230 
01231 // the mapping from bitfield in fsUsb (of FONTSIGNATURE) to UnicodeRange
01232 // defined in nsUnicodeRange.h. Only the first 96 bits are mapped here
01233 // because at the moment only the first 84 bits are assigned according to 
01234 // the MSDN. See 
01235 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp
01236 static PRUint8 gBitToUnicodeRange[] = 
01237 {
01238  /*  0 */ kRangeSetLatin,   // 0020 - 007e     Basic Latin
01239  /*  1 */ kRangeSetLatin,   // 00a0 - 00ff     Latin-1 Supplement
01240  /*  2 */ kRangeSetLatin,   // 0100 - 017f     Latin Extended-A
01241  /*  3 */ kRangeSetLatin,   // 0180 - 024f     Latin Extended-B
01242  /*  4 */ kRangeSetLatin,   // 0250 - 02af     IPA Extensions
01243  /*  5 */ kRangeSetLatin,   // 02b0 - 02ff     Spacing Modifier Letters
01244  /*  6 */ kRangeGreek,      // 0300 - 036f     Combining Diacritical Marks
01245  /*  7 */ kRangeGreek,      // 0370 - 03ff     Basic Greek
01246  /*  8 */ kRangeUnassigned, // Reserved
01247  /*  9 */ kRangeCyrillic,   // 0400 - 04ff     Cyrillic
01248  /* 10 */ kRangeArmenian,   // 0530 - 058f     Armenian
01249  /* 11 */ kRangeHebrew,     // 0590 - 05ff     Basic Hebrew
01250  /* 12 */ kRangeUnassigned, // Reserved
01251  /* 13 */ kRangeArabic,     // 0600 - 06ff     Basic Arabic
01252  /* 14 */ kRangeUnassigned, // Reserved
01253  /* 15 */ kRangeDevanagari, // 0900 - 097f     Devanagari
01254  /* 16 */ kRangeBengali,    // 0980 - 09ff     Bengali
01255  /* 17 */ kRangeGurmukhi,   // 0a00 - 0a7f     Gurmukhi
01256  /* 18 */ kRangeGujarati,   // 0a80 - 0aff     Gujarati
01257  /* 19 */ kRangeOriya,      // 0b00 - 0b7f     Oriya
01258  /* 20 */ kRangeTamil,      // 0b80 - 0bff     Tamil
01259  /* 21 */ kRangeTelugu,     // 0c00 - 0c7f     Telugu
01260  /* 22 */ kRangeKannada,    // 0c80 - 0cff     Kannada
01261  /* 23 */ kRangeMalayalam,  // 0d00 - 0d7f     Malayalam
01262  /* 24 */ kRangeThai,       // 0e00 - 0e7f     Thai
01263  /* 25 */ kRangeLao,        // 0e80 - 0eff     Lao
01264  /* 26 */ kRangeGeorgian,   // 10a0 - 10ff     Basic Georgian
01265  /* 27 */ kRangeUnassigned, // Reserved
01266  /* 28 */ kRangeKorean,     // 1100 - 11ff     Hangul Jamo
01267  /* 29 */ kRangeSetLatin,   // 1e00 - 1eff     Latin Extended Additional
01268  /* 30 */ kRangeGreek,      // 1f00 - 1fff     Greek Extended
01269  /* 31 */ kRangeSetLatin,   // 2000 - 206f     General Punctuation
01270  /* 32 */ kRangeSetLatin,   // 2070 - 209f     Subscripts and Superscripts
01271  /* 33 */ kRangeSetLatin,   // 20a0 - 20cf     Currency Symbols
01272  /* 34 */ kRangeSetLatin,   // 20d0 - 20ff     Comb. Diacrit. Marks for Symbols
01273  /* 35 */ kRangeSetLatin,   // 2100 - 214f     Letter-like Symbols
01274  /* 36 */ kRangeSetLatin,   // 2150 - 218f     Number Forms
01275  /* 37 */ kRangeSetLatin,   // 2190 - 21ff     Arrows
01276  /* 38 */ kRangeMathOperators,          // 2200 - 22ff     
01277  /* 39 */ kRangeMiscTechnical,          // 2300 - 23ff    
01278  /* 40 */ kRangeControlOpticalEnclose,  // 2400 - 243f     Control Pictures
01279  /* 41 */ kRangeControlOpticalEnclose,  // 2440 - 245f     OCR
01280  /* 42 */ kRangeControlOpticalEnclose,  // 2460 - 24ff     Enc. Alphanumerics
01281  /* 43 */ kRangeBoxBlockGeometrics,     // 2500 - 257f     Box Drawing
01282  /* 44 */ kRangeBoxBlockGeometrics,     // 2580 - 259f     Block Elements
01283  /* 45 */ kRangeBoxBlockGeometrics,     // 25a0 - 25ff     Geometric Shapes
01284  /* 46 */ kRangeMiscSymbols,            // 2600 - 26ff     
01285  /* 47 */ kRangeDingbats,               // 2700 - 27bf   
01286  /* 48 */ kRangeSetCJK,                 // 3000 - 303f     CJK Symb & Punct.
01287  /* 49 */ kRangeSetCJK,                 // 3040 - 309f     Hiragana
01288  /* 50 */ kRangeSetCJK,                 // 30a0 - 30ff     Katakana
01289  /* 51 */ kRangeSetCJK,                 // 3100 - 312f 31a0, - 31bf  Bopomofo
01290  /* 52 */ kRangeSetCJK,                 // 3130 - 318f     Hangul Comp. Jamo
01291  /* 53 */ kRangeSetCJK,                 // 3190 - 319f     CJK Miscellaneous
01292  /* 54 */ kRangeSetCJK,                 // 3200 - 32ff     Enc. CJK Letters
01293  /* 55 */ kRangeSetCJK,                 // 3300 - 33ff     CJK Compatibility
01294  /* 56 */ kRangeKorean,                 // ac00 - d7a3     Hangul
01295  /* 57 */ kRangeSurrogate,              // d800 - dfff     Surrogates. 
01296  /* 58 */ kRangeUnassigned,             // Reserved
01297  /* 59 */ kRangeSetCJK,                 // 4e00 - 9fff     CJK Ideographs
01298                                         // 2e80 - 2eff  2f00 - 2fdf Radicals
01299                                         // 2ff0 - 2fff     IDS
01300                                         // 3400 - 4dbf     CJK Ext. A
01301  /* 60 */ kRangePrivate,                // e000 - f8ff     PUA
01302  /* 61 */ kRangeSetCJK,                 // f900 - faff     CJK Compat. 
01303  /* 62 */ kRangeArabic,                 // fb00 - fb4f     Alpha. Presen. Forms
01304  /* 63 */ kRangeArabic,                 // fb50 - fdff     Arabic Presen. FormsA
01305  /* 64 */ kRangeArabic,                 // fe20 - fe2f     Combining Half Marks
01306  /* 65 */ kRangeArabic,                 // fe30 - fe4f     CJK Compat. Forms
01307  /* 66 */ kRangeArabic,                 // fe50 - fe6f     Small Form Variants
01308  /* 67 */ kRangeArabic,                 // fe70 - fefe     Arabic Presen. FormsB
01309  /* 68 */ kRangeSetCJK,                 // ff00 - ffef     Half/Fullwidth Forms
01310  /* 69 */ kRangeSpecials,               // fff0 - fffd     Specials
01311  /* 70 */ kRangeTibetan,                // 0f00 - 0fcf     Tibetan
01312  /* 71 */ kRangeSyriac,                 // 0700 - 074f     Syriac
01313  /* 72 */ kRangeThaana,                 // 0780 - 07bf     Thaana
01314  /* 73 */ kRangeSinhala,                // 0d80 - 0dff     Sinhala
01315  /* 74 */ kRangeMyanmar,                // 1000 - 109f     Myanmar
01316  /* 75 */ kRangeEthiopic,               // 1200 - 12bf     Ethiopic
01317  /* 76 */ kRangeCherokee,               // 13a0 - 13ff     Cherokee
01318  /* 77 */ kRangeCanadian,               // 1400 - 14df     Can. Aboriginal Syl.
01319  /* 78 */ kRangeOghamRunic,             // 1680 - 169f     Ogham
01320  /* 79 */ kRangeOghamRunic,             // 16a0 - 16ff     Runic
01321  /* 80 */ kRangeKhmer,                  // 1780 - 17ff     Khmer
01322  /* 81 */ kRangeMongolian,              // 1800 - 18af     Mongolian
01323  /* 82 */ kRangeBraillePattern,         // 2800 - 28ff     Braille
01324  /* 83 */ kRangeYi,                     // a000 - a48c     Yi Yi Radicals
01325  /* 84 */ kRangeUnassigned,             // Reserved
01326  /* 85 */ kRangeUnassigned,
01327  /* 86 */ kRangeUnassigned,
01328  /* 87 */ kRangeUnassigned,
01329  /* 88 */ kRangeUnassigned,
01330  /* 89 */ kRangeUnassigned,
01331  /* 90 */ kRangeUnassigned,
01332  /* 91 */ kRangeUnassigned,
01333  /* 92 */ kRangeUnassigned,
01334  /* 93 */ kRangeUnassigned,
01335  /* 94 */ kRangeUnassigned,
01336  /* 95 */ kRangeUnassigned
01337 };
01338 
01339 
01340 // Helper to determine if a font has a private encoding that we know something about
01341 static nsresult
01342 GetCustomEncoding(const char* aFontName, nsCString& aValue, PRBool* aIsWide)
01343 {
01344   // this is "MS P Gothic" in Japanese
01345   static const char* mspgothic=  
01346     "\x82\x6c\x82\x72 \x82\x6f\x83\x53\x83\x56\x83\x62\x83\x4e";
01347   // below is a list of common used name for startup
01348   if ( (!strcmp(aFontName, "Tahoma" )) ||
01349        (!strcmp(aFontName, "Arial" )) ||
01350        (!strcmp(aFontName, "Times New Roman" )) ||
01351        (!strcmp(aFontName, "Courier New" )) ||
01352        (!strcmp(aFontName, mspgothic )) )
01353     return NS_ERROR_NOT_AVAILABLE; // error means do not get a special encoding
01354 
01355   // XXX We need this kludge to deal with aFontName in CP949 when the locale 
01356   // is Korean until we figure out a way to get facename in US-ASCII
01357   // regardless of the current locale. We have no control over what 
01358   // EnumFontFamiliesEx() does.
01359   nsCAutoString name;
01360   if ( ::GetACP() != 949) 
01361     name.Assign(NS_LITERAL_CSTRING("encoding.") + nsDependentCString(aFontName) + NS_LITERAL_CSTRING(".ttf"));
01362   else {
01363     PRUnichar fname[LF_FACESIZE];
01364     fname[0] = 0;
01365     MultiByteToWideChar(CP_ACP, 0, aFontName,
01366     strlen(aFontName) + 1, fname, sizeof(fname)/sizeof(fname[0]));
01367     name.Assign(NS_LITERAL_CSTRING("encoding.") + NS_ConvertUCS2toUTF8(fname) + NS_LITERAL_CSTRING(".ttf"));
01368   }
01369 
01370   name.StripWhitespace();
01371   ToLowerCase(name);
01372 
01373   // if we have not init the property yet, init it right now.
01374   if (!gFontEncodingProperties)
01375     NS_LoadPersistentPropertiesFromURISpec(&gFontEncodingProperties,
01376       NS_LITERAL_CSTRING("resource://gre/res/fonts/fontEncoding.properties"));
01377 
01378   if (gFontEncodingProperties) {
01379     nsAutoString prop;
01380     nsresult rv = gFontEncodingProperties->GetStringProperty(name, prop);
01381     if (NS_SUCCEEDED(rv)) {
01382       aValue.AssignWithConversion(prop);
01383 
01384       // The encoding name of a wide NonUnicode font in fontEncoding.properties
01385       // has '.wide' suffix which has to be removed to get the actual encoding.
01386       *aIsWide = StringEndsWith(aValue, NS_LITERAL_CSTRING(".wide"));
01387       if (*aIsWide) {
01388         aValue.Truncate(aValue.Length()-5);
01389       }
01390     }
01391     return rv;
01392   }
01393   return NS_ERROR_NOT_AVAILABLE;
01394 }
01395 
01396 // This function uses the charset converter manager to get a pointer on the 
01397 // converter for the font whose name is given. The caller holds a reference
01398 // to the converter, and should take care of the release...
01399 static nsresult
01400 GetConverterCommon(const char* aEncoding, nsIUnicodeEncoder** aConverter)
01401 {
01402   *aConverter = nsnull;
01403   nsresult rv;
01404   rv = gCharsetManager->GetUnicodeEncoderRaw(aEncoding, aConverter);
01405   if (NS_FAILED(rv)) return rv;
01406   return (*aConverter)->SetOutputErrorBehavior((*aConverter)->kOnError_Replace, nsnull, '?');
01407 }
01408 
01409 static nsresult
01410 GetDefaultConverterForTTFSymbolEncoding(nsIUnicodeEncoder** aConverter)
01411 {
01412   return GetConverterCommon(DEFAULT_TTF_SYMBOL_ENCODING, aConverter);
01413 }
01414 
01415 static nsresult
01416 GetConverter(const char* aFontName, PRBool aNameQuirks,
01417   nsIUnicodeEncoder** aConverter, PRBool* aIsWide = nsnull)
01418 {
01419   *aConverter = nsnull;
01420 
01421   if (aNameQuirks) {
01422 #ifdef NS_DEBUG
01423     // we don't apply the quirky behavior to wide Non-Unicode fonts
01424     nsCAutoString value;
01425     PRBool isWide = PR_FALSE;
01426     NS_ASSERTION(NS_FAILED(GetCustomEncoding(aFontName, value, &isWide)) || !isWide,
01427                  "internal error -- shouldn't get here");
01428 #endif
01429     return GetDefaultConverterForTTFSymbolEncoding(aConverter);
01430   }
01431 
01432   nsCAutoString value;
01433   PRBool isWide = PR_FALSE;
01434   nsresult rv = GetCustomEncoding(aFontName, value, &isWide);
01435   if (NS_FAILED(rv)) return rv;
01436   if (aIsWide) {
01437     *aIsWide = isWide;
01438   }
01439 
01440   return GetConverterCommon(value.get(), aConverter);
01441 }
01442 
01443 // This function uses the charset converter manager to fill the map for the
01444 // font whose name is given
01445 static PRUint16*
01446 GetCCMapThroughConverter(const char* aFontName, PRBool aNameQuirks)
01447 {
01448   // see if we know something about the converter of this font 
01449   nsCOMPtr<nsIUnicodeEncoder> converter;
01450   if (NS_SUCCEEDED(GetConverter(aFontName, aNameQuirks, getter_AddRefs(converter)))) {
01451     nsCOMPtr<nsICharRepresentable> mapper(do_QueryInterface(converter));
01452     if (mapper)
01453       return MapperToCCMap(mapper);
01454   } 
01455   return nsnull;
01456 }
01457 
01458 static nsresult
01459 ConvertUnicodeToGlyph(const PRUnichar* aSrc,  PRInt32 aSrcLength, 
01460   PRInt32& aDestLength, nsIUnicodeEncoder* aConverter,
01461   PRBool aIsWide, nsAutoCharBuffer& aResult)
01462 {
01463   if (aIsWide && 
01464       NS_FAILED(aConverter->GetMaxLength(aSrc, aSrcLength, &aDestLength))) {
01465     return NS_ERROR_UNEXPECTED;
01466   }
01467 
01468   if (!aResult.EnsureElemCapacity(aDestLength)) return NS_ERROR_OUT_OF_MEMORY;
01469   char* str = aResult.get();
01470 
01471   aConverter->Convert(aSrc, &aSrcLength, str, &aDestLength);
01472 
01473 #ifdef IS_LITTLE_ENDIAN
01474   // Convert BE UCS2 to LE UCS2 for 'wide' fonts
01475   if (aIsWide) {
01476     char* pstr = str;
01477     while (pstr < str + aDestLength) {
01478       PRUint8 tmp = pstr[0];
01479       pstr[0] = pstr[1];
01480       pstr[1] = tmp;
01481       pstr += 2;  // swap every two bytes
01482     }
01483   }
01484 #endif
01485   return NS_OK;
01486 }
01487 
01488 class nsFontInfo : public PLHashEntry
01489 {
01490 public:
01491   nsFontInfo(eFontType aFontType, PRUint8 aCharset, PRUint16* aCCMap)
01492   {
01493     mType = aFontType;
01494     mCharset = aCharset;
01495     mCCMap = aCCMap;
01496 #ifdef MOZ_MATHML
01497     mCMAP.mData = nsnull;  // These are initializations to characterize
01498     mCMAP.mLength = -1;    // the first call to GetGlyphIndices().
01499 #endif
01500   };
01501 
01502   eFontType mType;
01503   PRUint8   mCharset;
01504   PRUint16* mCCMap;
01505 #ifdef MOZ_MATHML
01506   // We need to cache the CMAP for performance reasons. This
01507   // way, we can retrieve glyph indices without having to call
01508   // GetFontData() -- (with malloc/free) for every function call.
01509   // However, the CMAP is created *lazily* and is typically less than
01510   // 1K or 2K. If no glyph indices are requested for this font, the
01511   // mCMAP.mData array will never be created.
01512   nsCharacterMap mCMAP;
01513 #endif
01514 };
01515 
01516 /*-----------------------
01517 ** Hash table allocation
01518 **----------------------*/
01519 //-- Font Metrics
01520 PR_STATIC_CALLBACK(void*) fontmap_AllocTable(void *pool, size_t size)
01521 {
01522   return nsMemory::Alloc(size);
01523 }
01524 
01525 PR_STATIC_CALLBACK(void) fontmap_FreeTable(void *pool, void *item)
01526 {
01527   nsMemory::Free(item);
01528 }
01529 
01530 PR_STATIC_CALLBACK(PLHashEntry*) fontmap_AllocEntry(void *pool, const void *key)
01531 {
01532  return new nsFontInfo(eFontType_Unicode, DEFAULT_CHARSET, nsnull);
01533 }
01534 
01535 PR_STATIC_CALLBACK(void) fontmap_FreeEntry(void *pool, PLHashEntry *he, PRUint32 flag)
01536 {
01537   if (flag == HT_FREE_ENTRY)  {
01538     nsFontInfo *fontInfo = NS_STATIC_CAST(nsFontInfo *, he);
01539     if (fontInfo->mCCMap && (fontInfo->mCCMap != nsFontMetricsWin::gEmptyCCMap))
01540       FreeCCMap(fontInfo->mCCMap); 
01541 #ifdef MOZ_MATHML
01542     if (fontInfo->mCMAP.mData)
01543       nsMemory::Free(fontInfo->mCMAP.mData);
01544 #endif
01545     delete (nsString *) (he->key);
01546     delete fontInfo;
01547   }
01548 }
01549 
01550 PLHashAllocOps fontmap_HashAllocOps = {
01551   fontmap_AllocTable, fontmap_FreeTable,
01552   fontmap_AllocEntry, fontmap_FreeEntry
01553 };
01554 
01555 // See bug 167136. Characters included in the list (see one of included
01556 // files for the list) is the union of the set included in
01557 // SHOULD_BE_SPACE macro replaced by this list and the set compiled by
01558 // Keith Packard to use in fonts.conf of fontconfig package.
01559 // Some of this may not have to be here because they're filtered out before
01560 // reaching here. Needs further investigation. 
01561 #include "blank_glyph.ccmap"
01562 DEFINE_CCMAP(gCharsWithBlankGlyphCCMap, const);
01563 
01564 #define SHOULD_BE_SPACE_CHAR(ch)  (CCMAP_HAS_CHAR(gCharsWithBlankGlyphCCMap,ch))
01565 
01566 enum {
01567   eTTPlatformIDUnicode = 0,
01568   eTTPlatformIDMacintosh = 1,
01569   eTTPlatformIDMicrosoft = 3
01570 };
01571 enum {
01572   eTTMicrosoftEncodingSymbol = 0,
01573   eTTMicrosoftEncodingUnicode = 1,
01574   eTTMicrosoftEncodingUCS4 = 10
01575 };
01576 // the name of the following enum is from 
01577 // http://www.microsoft.com/typography/otspec/cmap.htm
01578 enum {
01579   eTTFormatUninitialize = -1,
01580   eTTFormat0ByteEncodingTable = 0,
01581   eTTFormat2HighbyteMappingThroughTable = 2,
01582   eTTFormat4SegmentMappingToDeltaValues = 4,
01583   eTTFormat6TrimmedTableMapping = 6,
01584   eTTFormat8Mixed16bitAnd32bitCoverage = 8,
01585   eTTFormat10TrimmedArray = 10,
01586   eTTFormat12SegmentedCoverage = 12
01587 };
01588 
01589 static void 
01590 ReadCMAPTableFormat12(PRUint8* aBuf, PRInt32 len, PRUint32 **aExtMap) 
01591 {
01592   PRUint8* p = aBuf;
01593   PRUint32 i;
01594 
01595   p += sizeof(PRUint16); // skip format
01596   p += sizeof(PRUint16); // skip reserve field
01597   p += sizeof(PRUint32); // skip tableLen
01598   p += sizeof(PRUint32); // skip language
01599   PRUint32 nGroup = GET_LONG(p);
01600   p += sizeof(PRUint32); 
01601 
01602   PRUint32 plane;
01603   PRUint32 startCode;
01604   PRUint32 endCode;
01605   PRUint32 c;
01606   for (i = 0; i < nGroup; i++) {
01607     startCode = GET_LONG(p);
01608     p += sizeof(PRUint32); 
01609     endCode = GET_LONG(p);
01610     p += sizeof(PRUint32); 
01611     for ( c = startCode; c <= endCode; ++c) {
01612       plane = c >> 16;
01613       if (!aExtMap[plane]) {
01614         aExtMap[plane] = new PRUint32[UCS2_MAP_LEN];
01615         if (!aExtMap[plane])
01616           return; // i.e., we will only retain the BMP and what we were able to allocate so far
01617         memset(aExtMap[plane], 0, sizeof(PRUint32) * UCS2_MAP_LEN);
01618       }
01619       ADD_GLYPH(aExtMap[plane], c & 0xffff);
01620     }
01621     p += sizeof(PRUint32); // skip startGlyphID  field
01622   }
01623 }
01624 
01625 
01626 static void 
01627 ReadCMAPTableFormat4(PRUint8* aBuf, PRInt32 aLength, PRUint32* aMap,
01628   PRBool aIsCFFOutline, PRUint8* aIsSpace, PRUint32 aMaxGlyph)
01629 {
01630   PRUint8* p = aBuf;
01631   PRUint8* end = aBuf + aLength;
01632   PRUint32 i;
01633 
01634   // XXX byte swapping only required for little endian (ifdef?)
01635   while (p < end) {
01636     PRUint8 tmp = p[0];
01637     p[0] = p[1];
01638     p[1] = tmp;
01639     p += 2; // every two bytes
01640   }
01641 
01642   PRUint16* s = (PRUint16*) aBuf;
01643   PRUint16 segCount = s[3] / 2;
01644   PRUint16* endCode = &s[7];
01645   PRUint16* startCode = endCode + segCount + 1;
01646   PRUint16* idDelta = startCode + segCount;
01647   PRUint16* idRangeOffset = idDelta + segCount;
01648 
01649   for (i = 0; i < segCount; ++i) {
01650     if (idRangeOffset[i]) {
01651       PRUint16 startC = startCode[i];
01652       PRUint16 endC = endCode[i];
01653       for (PRUint32 c = startC; c <= endC; ++c) {
01654         PRUint16* g =
01655           (idRangeOffset[i]/2 + (c - startC) + &idRangeOffset[i]);
01656         if ((PRUint8*) g < end) {
01657           if (*g) {
01658             PRUint16 glyph = idDelta[i] + *g;
01659             if (aIsCFFOutline) {
01660               ADD_GLYPH(aMap, c);
01661             }
01662             else if (glyph < aMaxGlyph) {
01663               if (aIsSpace[glyph]) {
01664                 if (SHOULD_BE_SPACE_CHAR(c)) {
01665                   ADD_GLYPH(aMap, c);
01666                 } 
01667               }
01668               else {
01669                 ADD_GLYPH(aMap, c);
01670               }
01671             }
01672           }
01673           else {
01674             // index 0 also applies to space character
01675             if (SHOULD_BE_SPACE_CHAR(c))
01676               ADD_GLYPH(aMap, c);
01677           }
01678         }
01679         else {
01680           // XXX should we trust this font at all if it does this?
01681         }
01682       }
01683       //printf("0x%04X-0x%04X ", startC, endC);
01684     }
01685     else {
01686       PRUint16 endC = endCode[i];
01687       for (PRUint32 c = startCode[i]; c <= endC; ++c) {
01688         PRUint16 glyph = idDelta[i] + c;
01689         if (aIsCFFOutline) {
01690           ADD_GLYPH(aMap, c);
01691         }
01692         else if (glyph < aMaxGlyph) {
01693           if (aIsSpace[glyph]) {
01694             if (SHOULD_BE_SPACE_CHAR(c)) {
01695               ADD_GLYPH(aMap, c);
01696             }
01697           }
01698           else {
01699             ADD_GLYPH(aMap, c);
01700           }
01701         }
01702       }
01703       //printf("0x%04X-0x%04X ", startCode[i], endC);
01704     }
01705   }
01706   //printf("\n");
01707 }
01708 
01709 PRUint16*
01710 nsFontMetricsWin::GetFontCCMAP(HDC aDC, const char* aShortName,
01711   PRBool aNameQuirks, eFontType& aFontType, PRUint8& aCharset)
01712 {
01713   PRUint16 *ccmap = nsnull;
01714 
01715   DWORD len = GetFontData(aDC, CMAP, 0, nsnull, 0);
01716   if ((len == GDI_ERROR) || (!len)) {
01717     return nsnull;
01718   }
01719   nsAutoFontDataBuffer buffer;
01720   if (!buffer.EnsureElemCapacity(len)) {
01721     return nsnull;
01722   }
01723   PRUint8* buf = buffer.get();
01724   DWORD newLen = GetFontData(aDC, CMAP, 0, buf, len);
01725   if (newLen != len) {
01726     return nsnull;
01727   }
01728 
01729   PRUint32 map[UCS2_MAP_LEN];
01730   memset(map, 0, sizeof(map));
01731   PRUint8* p = buf + sizeof(PRUint16); // skip version, move to numberSubtables
01732   PRUint16 n = GET_SHORT(p); // get numberSubtables
01733   p += sizeof(PRUint16); // skip numberSubtables, move to the encoding subtables
01734   PRUint16 i;
01735   PRUint32 keepOffset;
01736   PRUint32 offset;
01737   PRUint32 keepFormat = eTTFormatUninitialize;
01738 
01739   for (i = 0; i < n; ++i) {
01740     PRUint16 platformID = GET_SHORT(p); // get platformID
01741     p += sizeof(PRUint16); // move to platformSpecificID
01742     PRUint16 encodingID = GET_SHORT(p); // get platformSpecificID
01743     p += sizeof(PRUint16); // move to offset
01744     offset = GET_LONG(p);  // get offset
01745     p += sizeof(PRUint32); // move to next entry
01746     if (platformID == eTTPlatformIDMicrosoft) { 
01747       if (encodingID == eTTMicrosoftEncodingUnicode) { // Unicode
01748         // Some fonts claim to be unicode when they are actually
01749         // 'pseudo-unicode' fonts that require a converter...
01750         // Here, we check if this font is a pseudo-unicode font that 
01751         // we know something about, and we force it to be treated as
01752         // a non-unicode font.
01753         ccmap = GetCCMapThroughConverter(aShortName, aNameQuirks);
01754         if (ccmap) {
01755           aCharset = DEFAULT_CHARSET;
01756           aFontType = eFontType_NonUnicode;
01757           return ccmap;
01758         }
01759         PRUint16 format = GET_SHORT(buf+offset);
01760         if (format == eTTFormat4SegmentMappingToDeltaValues) {
01761           keepFormat = eTTFormat4SegmentMappingToDeltaValues;
01762           keepOffset = offset;
01763         }
01764       } // if (encodingID == eTTMicrosoftEncodingUnicode) 
01765       else if (encodingID == eTTMicrosoftEncodingSymbol) { // symbol
01766         aCharset = SYMBOL_CHARSET;
01767         aFontType = eFontType_NonUnicode;
01768         return GetCCMapThroughConverter(aShortName, aNameQuirks);
01769       } // if (encodingID == eTTMicrosoftEncodingSymbol)
01770       else if (encodingID == eTTMicrosoftEncodingUCS4) {
01771         PRUint16 format = GET_SHORT(buf+offset);
01772         if (format == eTTFormat12SegmentedCoverage) {
01773           keepFormat = eTTFormat12SegmentedCoverage;
01774           keepOffset = offset;
01775           // we don't want to try anything else when this format is available.
01776           break;
01777         }
01778       }
01779     } // if (platformID == eTTPlatformIDMicrosoft) 
01780   } // for loop
01781 
01782 
01783   if (eTTFormat12SegmentedCoverage == keepFormat) {
01784     PRUint32* extMap[EXTENDED_UNICODE_PLANES+1];
01785     extMap[0] = map;
01786     memset(extMap+1, 0, sizeof(PRUint32*)*EXTENDED_UNICODE_PLANES);
01787     ReadCMAPTableFormat12(buf+keepOffset, len-keepOffset, extMap);
01788     ccmap = MapToCCMapExt(map, extMap+1, EXTENDED_UNICODE_PLANES);
01789     for (i = 1; i <= EXTENDED_UNICODE_PLANES; ++i) {
01790       if (extMap[i])
01791         delete [] extMap[i];
01792     }
01793     aCharset = DEFAULT_CHARSET;
01794     aFontType = eFontType_Unicode;
01795   }
01796   else if (eTTFormat4SegmentMappingToDeltaValues == keepFormat) {
01797     PRUint32 maxGlyph;
01798     nsAutoFontDataBuffer isSpace;
01799     PRBool isCFFOutline;
01800     if (NS_SUCCEEDED(GetSpaces(aDC, &isCFFOutline, &maxGlyph, isSpace))) {
01801       ReadCMAPTableFormat4(buf+keepOffset, len-keepOffset, map, isCFFOutline,
01802         isSpace.get(), maxGlyph);
01803       ccmap = MapToCCMap(map);
01804       aCharset = DEFAULT_CHARSET;
01805       aFontType = eFontType_Unicode;
01806     }
01807   }
01808 
01809   return ccmap;
01810 }
01811 
01812 // Maps that are successfully returned by GetCCMAP() are also cached in the
01813 // gFontMaps hashtable and these are possibly shared. They are going to be
01814 // deleted by the cleanup observer. You don't need to delete a map upon
01815 // calling GetCCMAP (even if you subsequently fail to create a current font
01816 // with it). Otherwise, you will leave a dangling pointer in the gFontMaps
01817 // hashtable.
01818 PRUint16*
01819 nsFontMetricsWin::GetCCMAP(HDC aDC, const char* aShortName,
01820   PRBool* aNameQuirks, eFontType* aFontType, PRUint8* aCharset)
01821 {
01822   if (!gFontMaps) {
01823     gFontMaps = PL_NewHashTable(0, HashKey, CompareKeys, nsnull, &fontmap_HashAllocOps,
01824       nsnull);
01825     if (!gFontMaps) { // error checking
01826       return nsnull;
01827     }
01828     gEmptyCCMap = CreateEmptyCCMap();
01829     if (!gEmptyCCMap) {
01830       PL_HashTableDestroy(gFontMaps);
01831       gFontMaps = nsnull;
01832       return nsnull;
01833     }
01834   }
01835   eFontType fontType = aFontType ? *aFontType : eFontType_Unicode;
01836   PRUint8 charset = DEFAULT_CHARSET;
01837   nsString* name = new nsString(); // deleted by fontmap_FreeEntry
01838   if (!name) {
01839     return nsnull;
01840   }
01841   nsFontInfo* info;
01842   PLHashEntry *he, **hep = NULL; // shouldn't be NULL, using it as a flag to catch bad changes
01843   PLHashNumber hash;
01844   PRBool nameQuirks = aNameQuirks ? *aNameQuirks : PR_FALSE;
01845   PRBool isSymbolEncoding = PR_FALSE;
01846   eGetNameError ret = GetNAME(aDC, name, &isSymbolEncoding);
01847   if (ret == eGetName_OK) {
01848     // see if we should treat this name as a quirks name
01849     if (nameQuirks && (isSymbolEncoding || fontType != eFontType_Unicode)) {
01850       name->SetCharAt(PRUnichar('1'), 0); // change the prefix: name[0] = '1'
01851     }
01852     else {
01853       nameQuirks = PR_FALSE;
01854       if (aNameQuirks) {
01855         *aNameQuirks = PR_FALSE;
01856       }
01857     }
01858     // lookup the hashtable (if we miss, the computed hash and hep are fed back in HT-RawAdd)
01859     hash = HashKey(name);
01860     hep = PL_HashTableRawLookup(gFontMaps, hash, name);
01861     he = *hep;
01862     if (he) {
01863       // an identical map has already been added
01864       delete name;
01865       info = NS_STATIC_CAST(nsFontInfo *, he);
01866       if (aCharset) {
01867         *aCharset = info->mCharset;
01868       }
01869       if (aFontType) {
01870         *aFontType = info->mType;
01871       }
01872       return info->mCCMap;
01873     }
01874   }
01875   // GDIError occurs when we have raster font (not TrueType)
01876   else if (ret == eGetName_GDIError) {
01877     delete name;
01878     charset = GetTextCharset(aDC);
01879     if (charset & (~0xFF)) {
01880       return gEmptyCCMap;
01881     }
01882     int j = gCharsetToIndex[charset];
01883     
01884     //default charset is not dependable, skip it at this time
01885     if (j == eCharset_DEFAULT) {
01886       return gEmptyCCMap;
01887     }
01888     PRUint16* charsetCCMap = gCharsetInfo[j].mCCMap;
01889     if (!charsetCCMap) {
01890       charsetCCMap = gCharsetInfo[j].GenerateMap(&gCharsetInfo[j]);
01891       if (charsetCCMap)
01892         gCharsetInfo[j].mCCMap = charsetCCMap;
01893       else
01894         return gEmptyCCMap;
01895     }
01896     if (aCharset) {
01897       *aCharset = charset;
01898     }
01899     if (aFontType) {
01900       *aFontType = eFontType_Unicode;
01901     }
01902     return charsetCCMap;   
01903   }
01904   else {
01905     // return an empty map, so that we never try this font again
01906     delete name;
01907     return gEmptyCCMap;
01908   }
01909 
01910   if (aFontType)
01911     fontType = *aFontType;
01912   if (aCharset)
01913     charset = *aCharset;
01914   PRUint16* ccmap = GetFontCCMAP(aDC, aShortName, nameQuirks, fontType, charset);
01915   if (aFontType)
01916     *aFontType = fontType; 
01917   if (aCharset)
01918     *aCharset = charset;
01919 
01920   if (!ccmap) {
01921     delete name;
01922     return gEmptyCCMap;
01923   }
01924 
01925   // XXX Need to check if an identical map has already been added - Bug 75260
01926   NS_ASSERTION(hep, "bad code");
01927   he = PL_HashTableRawAdd(gFontMaps, hep, hash, name, nsnull);
01928   if (he) {
01929     info = NS_STATIC_CAST(nsFontInfo*, he);
01930     he->value = info;    // so PL_HashTableLookup returns an nsFontInfo*
01931     info->mType = fontType;
01932     info->mCharset = charset;
01933     info->mCCMap = ccmap;
01934     return ccmap;
01935   }
01936   delete name;
01937   return nsnull;
01938 }
01939 
01940 // The following function returns the glyph indices of a Unicode string.
01941 // To this end, GetGlyphIndices() retrieves the CMAP of the current font
01942 // in the DC:
01943 // 1) If the param aCMAP = nsnull, the function does not cache the CMAP.
01944 // 2) If the param aCMAP = address of a pointer on a nsCharacterMap
01945 // variable, and this is the first call, the function will cache
01946 // the CMAP in the gFontMaps hash table, and returns its location, hence
01947 // the caller can re-use the cached value in subsequent calls.
01948 static nsresult
01949 GetGlyphIndices(HDC                 aDC,
01950                 nsCharacterMap**    aCMAP,
01951                 const PRUnichar*    aString, 
01952                 PRUint32            aLength,
01953                 nsAutoChar16Buffer& aResult)
01954 {  
01955   NS_ASSERTION(aString, "null arg");
01956   if (!aString)
01957     return NS_ERROR_NULL_POINTER;
01958 
01959   nsAutoFontDataBuffer buffer;
01960   PRUint8* buf = nsnull;
01961   DWORD len = -1;
01962   
01963   // --------------
01964   // Dig for the Unicode subtable if this is the first call.
01965 
01966   if (!aCMAP || // the caller doesn't cache the CMAP, or
01967       !*aCMAP || (*aCMAP)->mLength < 0  // the CMAP is not yet initialized
01968      ) 
01969   {
01970     // Initialize as a 0-length CMAP, so that if there is an
01971     // error with this CMAP, it will never be tried again.
01972     if (aCMAP && *aCMAP) (*aCMAP)->mLength = 0; 
01973 
01974     len = GetFontData(aDC, CMAP, 0, nsnull, 0);
01975     if ((len == GDI_ERROR) || (!len)) {
01976       return NS_ERROR_UNEXPECTED;
01977     }
01978     if (!buffer.EnsureElemCapacity(len)) {
01979       return NS_ERROR_OUT_OF_MEMORY;
01980     }
01981     buf = buffer.get();
01982     DWORD newLen = GetFontData(aDC, CMAP, 0, buf, len);
01983     if (newLen != len) {
01984       return NS_ERROR_UNEXPECTED;
01985     }
01986     PRUint8* p = buf + sizeof(PRUint16); // skip version, move to numberOfSubtables
01987     PRUint16 n = GET_SHORT(p);
01988     p += sizeof(PRUint16); // skip numberSubtables, move to the encoding subtables
01989     PRUint16 i;
01990     PRUint32 offset;
01991     for (i = 0; i < n; ++i) {
01992       PRUint16 platformID = GET_SHORT(p); // get platformID
01993       p += sizeof(PRUint16); // move to platformSpecificID
01994       PRUint16 encodingID = GET_SHORT(p); // get platformSpecificID
01995       p += sizeof(PRUint16); // move to offset
01996       offset = GET_LONG(p);  // get offset
01997       p += sizeof(PRUint32); // move to next entry
01998       if (platformID == eTTPlatformIDMicrosoft && 
01999           encodingID == eTTMicrosoftEncodingUnicode) // Unicode
02000         break;
02001     }
02002     if (i == n) {
02003       NS_WARNING("nsFontMetricsWin::GetGlyphIndices() called for a non-unicode font!");
02004       return NS_ERROR_UNEXPECTED;
02005     }
02006     p = buf + offset;
02007     PRUint16 format = GET_SHORT(p);
02008     if (format != eTTFormat4SegmentMappingToDeltaValues) {
02009       return NS_ERROR_UNEXPECTED;
02010     }
02011     PRUint8* end = buf + len;
02012 
02013     // XXX byte swapping only required for little endian (ifdef?)
02014     while (p < end) {
02015       PRUint8 tmp = p[0];
02016       p[0] = p[1];
02017       p[1] = tmp;
02018       p += 2; // swap every two bytes
02019     }
02020 #ifdef MOZ_MATHML
02021     // cache these for later re-use
02022     if (aCMAP) {
02023       nsAutoString name;
02024       nsFontInfo* info;
02025       if (GetNAME(aDC, &name) == eGetName_OK) {
02026         info = (nsFontInfo*)PL_HashTableLookup(nsFontMetricsWin::gFontMaps, &name);
02027         if (info) {
02028           info->mCMAP.mData = (PRUint8*)nsMemory::Alloc(len);
02029           if (info->mCMAP.mData) {
02030             memcpy(info->mCMAP.mData, buf, len);
02031             info->mCMAP.mLength = len;
02032             *aCMAP = &(info->mCMAP);
02033           }          
02034         }
02035       }
02036     }
02037 #endif
02038   }
02039 
02040   // --------------
02041   // get glyph indices
02042 
02043   if (aCMAP && *aCMAP) { // recover cached CMAP if we have skipped the previous step
02044     buf = (*aCMAP)->mData;
02045     len = (*aCMAP)->mLength;
02046   }
02047   if (buf && len > 0) {
02048     // get the offset   
02049     PRUint8* p = buf + sizeof(PRUint16); // skip version, move to numberOfSubtables
02050     PRUint16 n = GET_SHORT(p);
02051     p += sizeof(PRUint16); // skip numberSubtables, move to the encoding subtables
02052     PRUint16 i;
02053     PRUint32 offset;
02054     for (i = 0; i < n; ++i) {
02055       PRUint16 platformID = GET_SHORT(p); // get platformID
02056       p += sizeof(PRUint16); // move to platformSpecificID
02057       PRUint16 encodingID = GET_SHORT(p); // get platformSpecificID
02058       p += sizeof(PRUint16); // move to offset
02059       offset = GET_LONG(p);  // get offset
02060       p += sizeof(PRUint32); // move to next entry
02061       if (platformID == eTTPlatformIDMicrosoft && 
02062           encodingID == eTTMicrosoftEncodingUnicode) // Unicode
02063         break;
02064     }
02065     PRUint8* end = buf + len;
02066 
02067     PRUint16* s = (PRUint16*) (buf + offset);
02068     PRUint16 segCount = s[3] / 2;
02069     PRUint16* endCode = &s[7];
02070     PRUint16* startCode = endCode + segCount + 1;
02071     PRUint16* idDelta = startCode + segCount;
02072     PRUint16* idRangeOffset = idDelta + segCount;
02073 
02074     if (!aResult.EnsureElemCapacity(aLength)) {
02075       return NS_ERROR_OUT_OF_MEMORY;
02076     }
02077     PRUnichar* result = aResult.get();
02078     for (i = 0; i < aLength; ++i) {
02079       result[i] = GetGlyphIndex(segCount, endCode, startCode,
02080                                 idRangeOffset, idDelta, end, 
02081                                 aString[i]);
02082     }
02083 
02084     return NS_OK;
02085   }
02086   return NS_ERROR_UNEXPECTED;
02087 }
02088 
02089 // ----------------------------------------------------------------------
02090 // We use GetGlyphOutlineW() or GetGlyphOutlineA() to get the metrics. 
02091 // GetGlyphOutlineW() is faster, but not implemented on all platforms.
02092 // nsGlyphAgent provides an interface to hide these details, and it
02093 // also hides the parameters/setup needed to call GetGlyphOutline.
02094 
02095 enum eGlyphAgent {
02096   eGlyphAgent_UNKNOWN = -1,
02097   eGlyphAgent_UNICODE,
02098   eGlyphAgent_ANSI
02099 };
02100 
02101 class nsGlyphAgent
02102 {
02103 public:
02104   nsGlyphAgent()
02105   {
02106     mState = eGlyphAgent_UNKNOWN;
02107     // set glyph transform matrix to identity
02108     FIXED zero, one;
02109     zero.fract = 0; one.fract = 0;
02110     zero.value = 0; one.value = 1; 
02111     mMat.eM12 = mMat.eM21 = zero;
02112     mMat.eM11 = mMat.eM22 = one;   
02113   }
02114 
02115   ~nsGlyphAgent()
02116   {}
02117 
02118   eGlyphAgent GetState()
02119   {
02120     return mState;
02121   }
02122 
02123   DWORD GetGlyphMetrics(HDC           aDC,
02124                         PRUint8       aChar,
02125                         GLYPHMETRICS* aGlyphMetrics);
02126 
02127   DWORD GetGlyphMetrics(HDC           aDC, 
02128                         PRUnichar     aChar,
02129                         PRUint16      aGlyphIndex,
02130                         GLYPHMETRICS* aGlyphMetrics);
02131 private:
02132   MAT2 mMat;    // glyph transform matrix (always identity in our context)
02133 
02134   eGlyphAgent mState; 
02135                 // eGlyphAgent_UNKNOWN : glyph agent is not yet fully initialized
02136                 // eGlyphAgent_UNICODE : this platform implements GetGlyphOutlineW()
02137                 // eGlyphAgent_ANSI : this platform doesn't implement GetGlyphOutlineW()
02138 };
02139 
02140 // Version of GetGlyphMetrics() for a non-Unicode font.
02141 // Here we use a simple wrapper on top of GetGlyphOutlineA().
02142 DWORD
02143 nsGlyphAgent::GetGlyphMetrics(HDC           aDC,
02144                               PRUint8       aChar,
02145                               GLYPHMETRICS* aGlyphMetrics)
02146 {
02147   memset(aGlyphMetrics, 0, sizeof(GLYPHMETRICS)); // UMR: bug 46438
02148   return GetGlyphOutlineA(aDC, aChar, GGO_METRICS, aGlyphMetrics, 0, nsnull, &mMat);
02149 }
02150 
02151 // Version of GetGlyphMetrics() for a Unicode font.
02152 // Here we use GetGlyphOutlineW() or GetGlyphOutlineA() to get the metrics. 
02153 // aGlyphIndex should be 0 if the caller doesn't know the glyph index of the char.
02154 DWORD
02155 nsGlyphAgent::GetGlyphMetrics(HDC           aDC,
02156                               PRUnichar     aChar,
02157                               PRUint16      aGlyphIndex,
02158                               GLYPHMETRICS* aGlyphMetrics)
02159 {
02160   memset(aGlyphMetrics, 0, sizeof(GLYPHMETRICS)); // UMR: bug 46438
02161   if (eGlyphAgent_UNKNOWN == mState) { // first time we have been in this function
02162     // see if this platform implements GetGlyphOutlineW()
02163     DWORD len = GetGlyphOutlineW(aDC, aChar, GGO_METRICS, aGlyphMetrics, 0, nsnull, &mMat);
02164     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
02165       // next time, we won't bother trying GetGlyphOutlineW()
02166       mState = eGlyphAgent_ANSI;
02167     }
02168     else {
02169       // all is well with GetGlyphOutlineW(), we will be using it from now on
02170       mState = eGlyphAgent_UNICODE;
02171       return len;
02172     }
02173   }
02174 
02175   if (eGlyphAgent_UNICODE == mState) {
02176     return GetGlyphOutlineW(aDC, aChar, GGO_METRICS, aGlyphMetrics, 0, nsnull, &mMat);
02177   }
02178 
02179   // Otherwise, we are on a platform that doesn't implement GetGlyphOutlineW()
02180   // (see Q241358: The GetGlyphOutlineW Function Fails on Windows 95 & 98
02181   // http://support.microsoft.com/support/kb/articles/Q241/3/58.ASP)
02182   // we will use glyph indices as a work around.
02183   if (0 == aGlyphIndex) { // caller doesn't know the glyph index, so find it
02184     nsAutoChar16Buffer buf;
02185     if (NS_SUCCEEDED(GetGlyphIndices(aDC, nsnull, &aChar, 1, buf)))
02186       aGlyphIndex = *(buf.get());
02187   }
02188   if (0 < aGlyphIndex) {
02189     return GetGlyphOutlineA(aDC, aGlyphIndex, GGO_METRICS | GGO_GLYPH_INDEX, aGlyphMetrics, 0, nsnull, &mMat);
02190   }
02191 
02192   // if we ever reach here, something went wrong in GetGlyphIndices() above
02193   // because the current font in aDC wasn't a Unicode font
02194   return GDI_ERROR;
02195 }
02196 
02197 // the global glyph agent that we will be using
02198 nsGlyphAgent gGlyphAgent;
02199 
02200 #ifdef MOZ_MATHML
02201 
02202 // the common part of GetBoundingMetrics used by nsFontWinUnicode
02203 // and 'wide' nsFontWinNonUnicode.
02204 static nsresult 
02205 GetBoundingMetricsCommon(HDC aDC, LONG aOverhangCorrection, const PRUnichar* aString, PRUint32 aLength, 
02206   nsBoundingMetrics& aBoundingMetrics, PRUnichar* aGlyphStr)
02207 {
02208   // measure the string
02209   nscoord descent;
02210   GLYPHMETRICS gm;                                                
02211   DWORD len = gGlyphAgent.GetGlyphMetrics(aDC, aString[0], aGlyphStr[0], &gm);
02212   if (GDI_ERROR == len) {
02213     return NS_ERROR_UNEXPECTED;
02214   }
02215   // flip sign of descent for cross-platform compatibility
02216   descent = -(nscoord(gm.gmptGlyphOrigin.y) - nscoord(gm.gmBlackBoxY));
02217   aBoundingMetrics.leftBearing = gm.gmptGlyphOrigin.x;
02218   aBoundingMetrics.rightBearing = gm.gmptGlyphOrigin.x + gm.gmBlackBoxX;
02219   aBoundingMetrics.ascent = gm.gmptGlyphOrigin.y;
02220   aBoundingMetrics.descent = descent;
02221   aBoundingMetrics.width = gm.gmCellIncX;
02222 
02223   if (1 < aLength) {
02224     // loop over each glyph to get the ascent and descent
02225     for (PRUint32 i = 1; i < aLength; ++i) {
02226       len = gGlyphAgent.GetGlyphMetrics(aDC, aString[i], aGlyphStr[i], &gm);
02227       if (GDI_ERROR == len) {
02228         return NS_ERROR_UNEXPECTED;
02229       }
02230       // flip sign of descent for cross-platform compatibility
02231       descent = -(nscoord(gm.gmptGlyphOrigin.y) - nscoord(gm.gmBlackBoxY));
02232       if (aBoundingMetrics.ascent < gm.gmptGlyphOrigin.y)
02233         aBoundingMetrics.ascent = gm.gmptGlyphOrigin.y;
02234       if (aBoundingMetrics.descent < descent)
02235         aBoundingMetrics.descent = descent;
02236     }
02237     // get the final rightBearing and width. Possible kerning is taken into account.
02238     SIZE size;
02239     ::GetTextExtentPointW(aDC, aString, aLength, &size);
02240     size.cx -= aOverhangCorrection;
02241     aBoundingMetrics.width = size.cx;
02242     aBoundingMetrics.rightBearing = size.cx - gm.gmCellIncX + gm.gmptGlyphOrigin.x + gm.gmBlackBoxX;
02243   }
02244 
02245   return NS_OK;
02246 }
02247 
02248 static nsresult 
02249 GetBoundingMetricsCommonA(HDC aDC, LONG aOverhangCorrection, const char* aString, PRUint32 aLength, 
02250   nsBoundingMetrics& aBoundingMetrics)
02251 {
02252   // measure the string
02253   nscoord descent;
02254   GLYPHMETRICS gm;
02255   DWORD len = gGlyphAgent.GetGlyphMetrics(aDC, PRUint8(aString[0]), &gm);
02256   if (GDI_ERROR == len) {
02257     return NS_ERROR_UNEXPECTED;
02258   }
02259 
02260   // flip sign of descent for cross-platform compatibility
02261   descent = -(nscoord(gm.gmptGlyphOrigin.y) - nscoord(gm.gmBlackBoxY));
02262   aBoundingMetrics.leftBearing = gm.gmptGlyphOrigin.x;
02263   aBoundingMetrics.rightBearing = gm.gmptGlyphOrigin.x + gm.gmBlackBoxX;
02264   aBoundingMetrics.ascent = gm.gmptGlyphOrigin.y;
02265   aBoundingMetrics.descent = descent;
02266   aBoundingMetrics.width = gm.gmCellIncX;
02267 
02268   if (1 < aLength) {
02269     // loop over each glyph to get the ascent and descent
02270     for (PRUint32 i = 1; i < aLength; ++i) {
02271       len = gGlyphAgent.GetGlyphMetrics(aDC, PRUint8(aString[i]), &gm);
02272       if (GDI_ERROR == len) {
02273         return NS_ERROR_UNEXPECTED;
02274       }
02275       // flip sign of descent for cross-platform compatibility
02276       descent = -(nscoord(gm.gmptGlyphOrigin.y) - nscoord(gm.gmBlackBoxY));
02277       if (aBoundingMetrics.ascent < gm.gmptGlyphOrigin.y)
02278         aBoundingMetrics.ascent = gm.gmptGlyphOrigin.y;
02279       if (aBoundingMetrics.descent < descent)
02280         aBoundingMetrics.descent = descent;
02281     }
02282     // get the final rightBearing and width. Possible kerning is taken into account.
02283     SIZE size;
02284     ::GetTextExtentPointA(aDC, aString, aLength, &size);
02285     size.cx -= aOverhangCorrection;
02286     aBoundingMetrics.width = size.cx;
02287     aBoundingMetrics.rightBearing = size.cx - gm.gmCellIncX + gm.gmBlackBoxX;
02288   }
02289 
02290   return NS_OK;
02291 }
02292 #endif
02293 
02294 // Subclass for common unicode fonts (e.g, Times New Roman, Arial, etc.).
02295 // Offers the fastest rendering because no mapping table is needed (here, 
02296 // unicode code points are identical to font's encoding indices). 
02297 // Uses 'W'ide functions (ExtTextOutW, GetTextExtentPoint32W).
02298 class nsFontWinUnicode : public nsFontWin
02299 {
02300 public:
02301   nsFontWinUnicode(LOGFONT* aLogFont, HFONT aFont, PRUint16* aCCMap);
02302   virtual ~nsFontWinUnicode();
02303 
02304   virtual PRInt32 GetWidth(HDC aDC, const PRUnichar* aString, PRUint32 aLength);
02305   virtual void DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
02306 
02307     const PRUnichar* aString, PRUint32 aLength);
02308 #ifdef MOZ_MATHML
02309   virtual nsresult
02310   GetBoundingMetrics(HDC                aDC,
02311                      const PRUnichar*   aString,
02312                      PRUint32           aLength,
02313                      nsBoundingMetrics& aBoundingMetrics);
02314 
02315 #ifdef NS_DEBUG
02316   virtual void DumpFontInfo();
02317 #endif // NS_DEBUG
02318 #endif
02319 
02320 private:
02321   PRBool mUnderlinedOrStrikeOut;
02322 };
02323 
02324 // Subclass for non-unicode fonts that need a mapping table. 'Narrow'
02325 // ones use 'A'nsi functions (ExtTextOutA, GetTextExtentPoint32A) after
02326 // converting unicode code points to font's encoding indices while
02327 // 'wide' ones use 'W' functions (ExtTextOutW, GetTextExtentPoint32W). 
02328 // (A slight  overhead arises from this conversion.)
02329 // NOTE: This subclass also handles some fonts that claim to be 
02330 // unicode, but need a converter.  Converter used for 'wide' fonts
02331 // among them is assumed to return the result in UCS2(BE) corresponding 
02332 // to  pseudo-Unicode code points used as 'glyph indices'(different from
02333 // genuine internal glyph indices used by a font)  of non-Unicode
02334 // fonts claiming to be Unicode fonts.
02335 class nsFontWinNonUnicode : public nsFontWin
02336 {
02337 public:
02338   nsFontWinNonUnicode(LOGFONT* aLogFont, HFONT aFont, PRUint16* aCCMap, nsIUnicodeEncoder* aConverter, PRBool aIsWide = PR_FALSE);
02339   virtual ~nsFontWinNonUnicode();
02340 
02341   virtual PRInt32 GetWidth(HDC aDC, const PRUnichar* aString, PRUint32 aLength);
02342   virtual void DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
02343                           const PRUnichar* aString, PRUint32 aLength);
02344 #ifdef MOZ_MATHML
02345   virtual nsresult
02346   GetBoundingMetrics(HDC                aDC,
02347                      const PRUnichar*   aString,
02348                      PRUint32           aLength,
02349                      nsBoundingMetrics& aBoundingMetrics);
02350 #ifdef NS_DEBUG
02351   virtual void DumpFontInfo();
02352 #endif // NS_DEBUG
02353 #endif
02354 
02355 private:
02356   nsCOMPtr<nsIUnicodeEncoder> mConverter;
02357   PRBool mIsWide; 
02358 };
02359 
02360 void
02361 nsFontMetricsWin::InitMetricsFor(HDC aDC, nsFontWin* aFont)
02362 {
02363   float dev2app;
02364   dev2app = mDeviceContext->DevUnitsToAppUnits();
02365 
02366   TEXTMETRIC metrics;
02367   ::GetTextMetrics(aDC, &metrics);
02368   aFont->mMaxAscent = NSToCoordRound(metrics.tmAscent * dev2app);
02369   aFont->mMaxDescent = NSToCoordRound(metrics.tmDescent * dev2app);
02370   aFont->mOverhangCorrection = 0;
02371   if (IsWin95OrWin98()) {
02372     aFont->mOverhangCorrection = metrics.tmOverhang;
02373     if (metrics.tmOverhang < 3 && metrics.tmItalic &&
02374         !(metrics.tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE | TMPF_DEVICE))) {
02375       // bug 216670 - for several italicized bitmap fonts, we have to compute
02376       // a overhang value, since the built-in value is zero if the weight of
02377       // the font is normal or it is one if the weight of the font is bold.
02378       SIZE size;
02379       ::GetTextExtentPoint32(aDC, " ", 1, &size);
02380       if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
02381         // optimization for monospace fonts: no need to make another GDI call.
02382         // We can use tmAveCharWidth since it does not include the overhang.
02383         aFont->mOverhangCorrection = size.cx - metrics.tmAveCharWidth;
02384       } else {
02385         SIZE size2;
02386         ::GetTextExtentPoint32(aDC, "  ", 2, &size2);
02387         aFont->mOverhangCorrection = size.cx * 2 - size2.cx;
02388       }
02389     }
02390   }
02391   aFont->mMaxCharWidthMetric = metrics.tmMaxCharWidth;
02392   aFont->mMaxHeightMetric = metrics.tmHeight;
02393   aFont->mPitchAndFamily = metrics.tmPitchAndFamily;
02394 }
02395 
02396 HFONT
02397 nsFontMetricsWin::CreateFontAdjustHandle(HDC aDC, LOGFONT* aLogFont)
02398 {
02399   // Adjust the aspect-value so that the x-height of the final font
02400   // is mFont.size * mFont.sizeAdjust
02401 
02402   PRInt32 dummy = 0;
02403   nscoord baseSize = mFont.size; 
02404   nscoord size72 = NSIntPointsToTwips(72); // large value improves accuracy
02405   mFont.size = size72;
02406   nscoord baselfHeight = aLogFont->lfHeight;
02407   FillLogFont(aLogFont, dummy, PR_TRUE);
02408 
02409   HFONT hfont = ::CreateFontIndirect(aLogFont);
02410   mFont.size = baseSize;
02411   aLogFont->lfHeight = baselfHeight;
02412 
02413   if (hfont) {
02414     HFONT oldFont = (HFONT)::SelectObject(aDC, (HGDIOBJ)hfont);
02415     char name[sizeof(aLogFont->lfFaceName)];
02416     if (::GetTextFace(aDC, sizeof(name), name) &&
02417         !strcmpi(name, aLogFont->lfFaceName)) {
02418       float dev2app;
02419       dev2app = mDeviceContext->DevUnitsToAppUnits();
02420 
02421       // Get the x-height
02422       nscoord xheight72;
02423       OUTLINETEXTMETRIC oMetrics;
02424       TEXTMETRIC& metrics = oMetrics.otmTextMetrics;
02425       if (0 < ::GetOutlineTextMetrics(aDC, sizeof(oMetrics), &oMetrics)) {
02426         xheight72 = NSToCoordRound((float)metrics.tmAscent * dev2app * 0.56f); // 50% of ascent, best guess for true type
02427         GLYPHMETRICS gm;
02428         DWORD len = gGlyphAgent.GetGlyphMetrics(aDC, PRUnichar('x'), 0, &gm);
02429         if (GDI_ERROR != len && gm.gmptGlyphOrigin.y > 0) {
02430           xheight72 = NSToCoordRound(gm.gmptGlyphOrigin.y * dev2app);
02431         }
02432       }
02433       else {
02434         ::GetTextMetrics(aDC, &metrics);
02435         xheight72 = NSToCoordRound((float)metrics.tmAscent * dev2app * 0.56f); // 56% of ascent, best guess for non-true type
02436       }
02437       ::SelectObject(aDC, (HGDIOBJ)oldFont);  
02438 
02439       // Apply the adjustment
02440       float adjust = mFont.sizeAdjust / (float(xheight72) / float(size72));
02441       mFont.size = NSToCoordRound(float(baseSize) * adjust);
02442       FillLogFont(aLogFont, dummy, PR_TRUE);
02443 
02444       hfont = ::CreateFontIndirect(aLogFont);
02445 
02446       // restore the original values before leaving
02447       mFont.size = baseSize;
02448       aLogFont->lfHeight = baselfHeight;
02449       return hfont;
02450     }
02451     ::SelectObject(aDC, (HGDIOBJ)oldFont);  
02452     ::DeleteObject((HFONT)hfont);  
02453   }
02454   return nsnull;
02455 }
02456 
02457 HFONT
02458 nsFontMetricsWin::CreateFontHandle(HDC aDC, const nsString& aName, LOGFONT* aLogFont)
02459 {
02460   PRUint16 weightTable = LookForFontWeightTable(aDC, aName);
02461   PRInt32 weight = GetFontWeight(mFont.weight, weightTable);
02462 
02463   FillLogFont(aLogFont, weight);
02464  
02465   // The risk of losing characters not covered by the current codepage 
02466   // is reduced because LookupWinFontName invoked earlier has taken care 
02467   // of most cases. 
02468   WideCharToMultiByte(CP_ACP, 0, aName.get(), aName.Length() + 1,
02469                       aLogFont->lfFaceName, sizeof(aLogFont->lfFaceName),
02470                       nsnull, nsnull);
02471 
02472   if (mFont.sizeAdjust <= 0) {
02473     // Quick return for the common case where no adjustement is needed
02474     return ::CreateFontIndirect(aLogFont);
02475   }
02476   return CreateFontAdjustHandle(aDC, aLogFont);
02477 }
02478 
02479 HFONT
02480 nsFontMetricsWin::CreateFontHandle(HDC aDC, nsGlobalFont* aGlobalFont, LOGFONT* aLogFont)
02481 {
02482   PRUint16 weightTable = LookForFontWeightTable(aDC, aGlobalFont->name);
02483   PRInt32 weight = GetFontWeight(mFont.weight, weightTable);
02484 
02485   FillLogFont(aLogFont, weight);
02486   aLogFont->lfCharSet = aGlobalFont->logFont.lfCharSet;
02487   aLogFont->lfPitchAndFamily = aGlobalFont->logFont.lfPitchAndFamily;
02488   strcpy(aLogFont->lfFaceName, aGlobalFont->logFont.lfFaceName);
02489 
02490   if (mFont.sizeAdjust <= 0) {
02491     // Quick return for the common case where no adjustement is needed
02492     return ::CreateFontIndirect(aLogFont);
02493   }
02494   return CreateFontAdjustHandle(aDC, aLogFont);
02495 }
02496 
02497 nsFontWin*
02498 nsFontMetricsWin::LoadFont(HDC aDC, const nsString& aName, PRBool aNameQuirks)
02499 {
02500   LOGFONT logFont;
02501   HFONT hfont = CreateFontHandle(aDC, aName, &logFont);
02502   if (hfont) {
02503     HFONT oldFont = (HFONT)::SelectObject(aDC, (HGDIOBJ)hfont);
02504     char name[sizeof(logFont.lfFaceName)];
02505     if (::GetTextFace(aDC, sizeof(name), name) &&
02506         !strcmpi(name, logFont.lfFaceName)) {
02507       nsFontWin* font = nsnull;
02508       if (mIsUserDefined) {
02509 #ifndef WINCE
02510         font = new nsFontWinNonUnicode(&logFont, hfont, gUserDefinedCCMap,
02511                                        gUserDefinedConverter);
02512 #else
02513         font = new nsFontWinUnicode(&logFont, hfont, gUserDefinedCCMap);
02514 #endif
02515     } else {
02516         eFontType fontType = eFontType_Unicode;
02517         PRBool nameQuirks = aNameQuirks;
02518         // see if we should override the quirks -- not all fonts are treated as quirks
02519         if (nameQuirks) {
02520           nsCAutoString encoding;
02521           PRBool isWide = PR_FALSE;
02522           if (NS_SUCCEEDED(GetCustomEncoding(logFont.lfFaceName, encoding, &isWide))) {
02523             nameQuirks = !isWide;
02524             fontType = eFontType_NonUnicode;
02525           }
02526         }
02527         PRUint16* ccmap = GetCCMAP(aDC, logFont.lfFaceName, &nameQuirks,
02528                                    &fontType, nsnull);
02529         if (ccmap) {
02530           if (eFontType_Unicode == fontType) {
02531             font = new nsFontWinUnicode(&logFont, hfont, ccmap);
02532           }
02533           else if (eFontType_NonUnicode == fontType) {
02534             PRBool isWide = PR_FALSE;
02535             nsCOMPtr<nsIUnicodeEncoder> converter;
02536             if (NS_SUCCEEDED(GetConverter(logFont.lfFaceName, nameQuirks,
02537                   getter_AddRefs(converter), &isWide)))
02538 #ifndef WINCE
02539                font = new nsFontWinNonUnicode(&logFont, hfont, ccmap, converter, isWide);
02540 #else
02541                font = new nsFontWinUnicode(&logFont, hfont, ccmap);
02542 #endif
02543           }
02544         }
02545       }
02546 
02547       if (font) {
02548         InitMetricsFor(aDC, font);
02549         mLoadedFonts.AppendElement(font);
02550         ::SelectObject(aDC, (HGDIOBJ)oldFont);  
02551         return font;
02552       }
02553       // do not free 'ccmap', it is cached in the gFontMaps hashtable and
02554       // it is going to be deleted by the cleanup observer
02555     }
02556     ::SelectObject(aDC, (HGDIOBJ)oldFont);
02557     ::DeleteObject(hfont);
02558   }
02559   return nsnull;
02560 }
02561 
02562 nsFontWin*
02563 nsFontMetricsWin::LoadGlobalFont(HDC aDC, nsGlobalFont* aGlobalFont)
02564 {
02565   LOGFONT logFont;
02566   HFONT hfont = CreateFontHandle(aDC, aGlobalFont, &logFont);
02567   if (hfont) {
02568     nsFontWin* font = nsnull;
02569     if (eFontType_Unicode == aGlobalFont->fonttype) {
02570       font = new nsFontWinUnicode(&logFont, hfont, aGlobalFont->ccmap);
02571     }
02572     else if (eFontType_NonUnicode == aGlobalFont->fonttype) {
02573       nsCOMPtr<nsIUnicodeEncoder> converter;
02574       PRBool isWide;
02575       if (NS_SUCCEEDED(GetConverter(logFont.lfFaceName, PR_FALSE,
02576             getter_AddRefs(converter), &isWide))) {
02577 #ifndef WINCE
02578         font = new nsFontWinNonUnicode(&logFont, hfont, aGlobalFont->ccmap, converter, isWide);
02579 #else
02580         font = new nsFontWinUnicode(&logFont, hfont, aGlobalFont->ccmap);
02581 #endif
02582       }
02583     }
02584     if (font) {
02585       HFONT oldFont = (HFONT)::SelectObject(aDC, (HGDIOBJ)hfont);
02586       InitMetricsFor(aDC, font);
02587       mLoadedFonts.AppendElement(font);
02588       ::SelectObject(aDC, (HGDIOBJ)oldFont);
02589       return font;
02590     }
02591     ::DeleteObject((HGDIOBJ)hfont);
02592   }
02593   return nsnull;
02594 }
02595 
02596 static int CALLBACK 
02597 enumProc(const LOGFONT* logFont, const TEXTMETRIC* metrics,
02598          DWORD fontType, LPARAM hasFontSig)
02599 {
02600   // XXX ignore vertical fonts
02601   if (logFont->lfFaceName[0] == '@') {
02602     return 1;
02603   }
02604 
02605   for (int i = nsFontMetricsWin::gGlobalFonts->Count()-1; i >= 0; --i) {
02606     nsGlobalFont* font = (nsGlobalFont*)nsFontMetricsWin::gGlobalFonts->ElementAt(i);
02607     if (!strcmp(font->logFont.lfFaceName, logFont->lfFaceName)) {
02608       // work-around for Win95/98 problem 
02609       int charsetSigBit = gCharsetToBit[gCharsetToIndex[logFont->lfCharSet]];
02610       if (charsetSigBit >= 0) {
02611         DWORD charsetSigAdd = 1 << charsetSigBit;
02612         font->signature.fsCsb[0] |= charsetSigAdd;
02613       }
02614 
02615       // copy Unicode subrange bitfield (128bit) if it's a truetype font. 
02616       if (fontType & hasFontSig) {
02617 #ifndef WINCE
02618         memcpy(font->signature.fsUsb, ((NEWTEXTMETRICEX*)metrics)->ntmFontSig.fsUsb, 16);
02619 #else
02620         memset(font->signature.fsUsb, '\0', 16);
02621 #endif
02622       }
02623       return 1;
02624     }
02625   }
02626 
02627   // XXX make this smarter: don't add font to list if we already have a font
02628   // with the same font signature -- erik
02629 
02630   PRUnichar name[LF_FACESIZE];
02631   name[0] = 0;
02632   MultiByteToWideChar(CP_ACP, 0, logFont->lfFaceName,
02633     strlen(logFont->lfFaceName) + 1, name, sizeof(name)/sizeof(name[0]));
02634 
02635   nsGlobalFont* font = new nsGlobalFont;
02636   if (!font) {
02637     return 0;
02638   }
02639   font->name.Assign(name);
02640   font->ccmap = nsnull;
02641   font->logFont = *logFont;
02642   font->signature.fsCsb[0] = 0;
02643   font->signature.fsCsb[1] = 0;
02644   font->fonttype = eFontType_UNKNOWN;
02645   font->flags = 0;
02646 
02647   if (fontType & hasFontSig) {
02648     font->flags |= NS_GLOBALFONT_TRUETYPE;
02649 #ifndef WINCE
02650     // copy Unicode subrange bitfield (128 bits = 16 bytes)
02651     memcpy(font->signature.fsUsb, ((NEWTEXTMETRICEX*)metrics)->ntmFontSig.fsUsb, 16);
02652 #else
02653     memset(font->signature.fsUsb, '\0', 16);
02654 #endif
02655   }
02656 
02657   if (logFont->lfCharSet == SYMBOL_CHARSET) {
02658     font->flags |= NS_GLOBALFONT_SYMBOL;
02659   }
02660 
02661   int charsetSigBit = gCharsetToBit[gCharsetToIndex[logFont->lfCharSet]];
02662   if (charsetSigBit >= 0) {
02663     DWORD charsetSigAdd = 1 << charsetSigBit;
02664     font->signature.fsCsb[0] |= charsetSigAdd;
02665   }
02666 
02667   nsFontMetricsWin::gGlobalFonts->AppendElement(font);
02668   return 1;
02669 }
02670 
02671 static int PR_CALLBACK
02672 CompareGlobalFonts(const void* aArg1, const void* aArg2, void* aClosure)
02673 {
02674   const nsGlobalFont* font1 = (const nsGlobalFont*)aArg1;
02675   const nsGlobalFont* font2 = (const nsGlobalFont*)aArg2;
02676 
02677   // Sorting criteria is like a tree:
02678   // + TrueType fonts
02679   //    + non-Symbol fonts
02680   //    + Symbol fonts
02681   // + non-TrueType fonts
02682   //    + non-Symbol fonts
02683   //    + Symbol fonts
02684   PRInt32 weight1 = 0, weight2 = 0; // computed as node mask 
02685   if (!(font1->flags & NS_GLOBALFONT_TRUETYPE))
02686     weight1 |= 0x2;
02687   if (!(font2->flags & NS_GLOBALFONT_TRUETYPE))
02688     weight2 |= 0x2; 
02689   if (font1->flags & NS_GLOBALFONT_SYMBOL)
02690     weight1 |= 0x1;
02691   if (font2->flags & NS_GLOBALFONT_SYMBOL)
02692     weight2 |= 0x1;
02693 
02694   return weight1 - weight2;
02695 }
02696 
02697 nsVoidArray*
02698 nsFontMetricsWin::InitializeGlobalFonts(HDC aDC)
02699 {
02700   if (!gGlobalFonts) {
02701     gGlobalFonts = new nsVoidArray();
02702     if (!gGlobalFonts) return nsnull;
02703 
02704     LOGFONT logFont;
02705     logFont.lfCharSet = DEFAULT_CHARSET;
02706     logFont.lfFaceName[0] = 0;
02707     logFont.lfPitchAndFamily = 0;
02708 
02709     /*
02710      * msdn.microsoft.com/library states that
02711      * EnumFontFamiliesExW is only on NT4+
02712      */
02713     EnumFontFamiliesEx(aDC, &logFont, enumProc, TRUETYPE_FONTTYPE, 0);
02714     if (gGlobalFonts->Count() == 0)
02715       EnumFontFamilies(aDC, nsnull, enumProc, 0);
02716 
02717     // Sort the global list of fonts to put the 'preferred' fonts first
02718     gGlobalFonts->Sort(CompareGlobalFonts, nsnull);
02719   }
02720 
02721   return gGlobalFonts;
02722 }
02723 
02724 int
02725 nsFontMetricsWin::SameAsPreviousMap(int aIndex)
02726 {
02727   // aIndex is 0...gGlobalFonts.Count()-1 in caller
02728   nsGlobalFont* font = (nsGlobalFont*)gGlobalFonts->ElementAt(aIndex);
02729   for (int i = 0; i < aIndex; ++i) {
02730     nsGlobalFont* tmp = (nsGlobalFont*)gGlobalFonts->ElementAt(i);
02731     if (tmp->flags & NS_GLOBALFONT_SKIP) {
02732       continue;
02733     }
02734     if (!tmp->ccmap) {
02735       continue;
02736     }
02737     if (tmp->ccmap == font->ccmap) {
02738       font->flags |= NS_GLOBALFONT_SKIP;
02739       return 1;
02740     }
02741 
02742     if (IsSameCCMap(tmp->ccmap, font->ccmap)) {
02743       font->flags |= NS_GLOBALFONT_SKIP;
02744       return 1;
02745     }
02746   }
02747 
02748   return 0;
02749 }
02750 
02751 #ifndef WINCE
02752 static
02753 void BitFromUnicodeRange(PRUint32 range, DWORD* usb)
02754 {
02755   for (int i = 0, dword = 0; dword < 3; ++dword) {
02756     for (int bit = 0; bit < sizeof(DWORD) * 8; ++bit, ++i) {
02757       if (range == gBitToUnicodeRange[i]) {
02758         usb[dword] |= 1 << bit;
02759       }
02760     }
02761   }
02762 }
02763 #endif
02764 
02765 #ifdef DEBUG_emk
02766 static LARGE_INTEGER freq, prev;
02767 #endif
02768 
02769 nsFontWin*
02770 nsFontMetricsWin::FindGlobalFont(HDC aDC, PRUint32 c)
02771 {
02772   //now try global font
02773   if (!gGlobalFonts) {
02774     if (!InitializeGlobalFonts(aDC)) {
02775       return nsnull;
02776     }
02777   }
02778 #ifndef WINCE
02779   PRUint32 range = (c <= 0xFFFF) ? FindCharUnicodeRange(c) : kRangeSurrogate;
02780   DWORD usb[4];
02781   memset(usb, 0, sizeof(usb));
02782   BitFromUnicodeRange(range, usb);
02783 #endif
02784   int count = gGlobalFonts->Count();
02785   for (int i = 0; i < count; ++i) {
02786     nsGlobalFont* font = (nsGlobalFont*)gGlobalFonts->ElementAt(i);
02787     if (font->flags & NS_GLOBALFONT_SKIP) {
02788       continue;
02789     }
02790     if (!font->ccmap) {
02791 #ifndef WINCE
02792       // bail out if Unicode range indicates the font have no glyph
02793       if (font->flags & NS_GLOBALFONT_TRUETYPE &&
02794           !(font->signature.fsUsb[0] & usb[0]) &&
02795           !(font->signature.fsUsb[1] & usb[1]) &&
02796           !(font->signature.fsUsb[2] & usb[2])) {
02797         continue;
02798       }
02799 #endif
02800       // don't adjust here, we just want to quickly get the CMAP. Adjusting
02801       // is meant to only happen when loading the final font in LoadFont()
02802       HFONT hfont = ::CreateFontIndirect(&font->logFont);
02803       if (!hfont) {
02804         continue;
02805       }
02806       HFONT oldFont = (HFONT)::SelectObject(aDC, hfont);
02807       font->ccmap = GetCCMAP(aDC, font->logFont.lfFaceName, 
02808         nsnull, &font->fonttype, nsnull);
02809       ::SelectObject(aDC, oldFont);
02810       ::DeleteObject(hfont);
02811       if (!font->ccmap || font->ccmap == gEmptyCCMap) {
02812         font->flags |= NS_GLOBALFONT_SKIP;
02813         continue;
02814       }
02815 #ifdef DEBUG_emk
02816       LARGE_INTEGER now;
02817       QueryPerformanceCounter(&now);
02818       printf("CCMAP loaded: %g sec, %s [%08X][%08X][%08X]\n", (now.QuadPart - prev.QuadPart) / (double)freq.QuadPart,
02819         font->logFont.lfFaceName, font->signature.fsUsb[0], font->signature.fsUsb[1], font->signature.fsUsb[2]);
02820       prev = now;
02821 #endif
02822       if (SameAsPreviousMap(i)) {
02823         continue;
02824       }
02825     }
02826     if (CCMAP_HAS_CHAR_EXT(font->ccmap, c)) {
02827 #ifdef DEBUG_emk
02828       printf("font found:[%s]\n", font->logFont.lfFaceName);
02829       printf("U+%04X (%d)[%08X][%08X][%08X]\n", c, range, usb[0], usb[1], usb[2]);
02830 #endif
02831       return LoadGlobalFont(aDC, font);
02832     }
02833   }
02834 #ifdef DEBUG_emk
02835   printf("U+%04X (%d)[%08X][%08X][%08X]\n", c, range, usb[0], usb[1], usb[2]);
02836 #endif
02837   return nsnull;
02838 }
02839 
02840 // XXX perf: also sync a static global map of missing chars, and check the
02841 // map to see if we can skip the lookup in FindGlobalFont(), and remember
02842 // to clear the map in UpdateFontList() when new fonts are installed
02843 nsFontWin*
02844 nsFontMetricsWin::FindSubstituteFont(HDC aDC, PRUint32 c)
02845 {
02846   /*
02847   When this function is called, it means all other alternatives have
02848   been unsuccessfully tried! So the idea is this:
02849   
02850   See if the "substitute font" is already loaded?
02851   a/ if yes, ADD_GLYPH(c), to record that the font should be used
02852      to render this char from now on. 
02853   b/ if no, load the font, and ADD_GLYPH(c)
02854   */
02855 
02856   // Assumptions: 
02857   // The nsFontInfo of the "substitute font" is not in the hashtable!
02858   // This way, its name doesn't matter since it cannot be retrieved with
02859   // a lookup in the hashtable. We only know its entry in mLoadedFonts[]
02860   // (Notice that the nsFontInfo of the font that is picked as the
02861   // "substitute font" *can* be in the hashtable, and as expected, its 
02862   // own map can be retrieved with the normal lookup).
02863 
02864   // The "substitute font" is a *unicode font*. No conversion here.
02865   // XXX Is it worth having another subclass which has a converter? 
02866   // Such a variant may allow to display a boxed question mark, etc.
02867 
02868   if (mSubstituteFont) {
02869     //make the char representable so that we don't have to go over all font before fallback to 
02870     //subsituteFont.
02871     ((nsFontWinSubstitute*)mSubstituteFont)->SetRepresentable(c);
02872     return mSubstituteFont;
02873   }
02874 
02875   // The "substitute font" has not yet been created... 
02876   // The first unicode font (no converter) that has the
02877   // replacement char is taken and placed as the substitute font.
02878 
02879   // Try local/loaded fonts first
02880   int i, count = mLoadedFonts.Count();
02881   for (i = 0; i < count; ++i) {
02882     nsAutoString name;
02883     nsFontWin* font = (nsFontWin*)mLoadedFonts[i];
02884 
02885     if (!font->mFont)
02886       continue;
02887 
02888     HFONT oldFont = (HFONT)::SelectObject(aDC, font->mFont);
02889     eGetNameError res = GetNAME(aDC, &name);
02890     ::SelectObject(aDC, oldFont);
02891     if (res == eGetName_OK) { // TrueType font
02892       nsFontInfo* info = (nsFontInfo*)PL_HashTableLookup(gFontMaps, &name);
02893       if (!info || info->mType != eFontType_Unicode) {
02894         continue;
02895       }
02896     }
02897     else if (res == eGetName_GDIError) { // Bitmap font
02898       // alright, was treated as unicode font in GetCCMAP()
02899 
02900 #ifdef WINCE
02901       name.AssignWithConversion(font->mName);
02902       font = LoadSubstituteFont(aDC, name);
02903       if (font) {
02904         ((nsFontWinSubstitute*)font)->SetRepresentable(c);
02905         mSubstituteFont = font;
02906         return font;
02907       }
02908 #endif
02909     }
02910     else {
02911       continue;
02912     }
02913     if (font->HasGlyph(NS_REPLACEMENT_CHAR)) {
02914       // XXX if the mode is to display unicode points "&#xNNNN;", should we check
02915       // that the substitute font also has glyphs for '&', '#', 'x', ';' and digits?
02916       // (Because this is a unicode font, those glyphs should in principle be there.)
02917       name.AssignWithConversion(font->mName);
02918       font = LoadSubstituteFont(aDC, name);
02919       if (font) {
02920         ((nsFontWinSubstitute*)font)->SetRepresentable(c);
02921         mSubstituteFont = font;
02922         return font;
02923       }
02924     }
02925   }
02926 
02927   // Try global fonts
02928   // Since we reach here after FindGlobalFont() is called, we have already
02929   // scanned the global list of fonts and have set the attributes of interest
02930   count = gGlobalFonts->Count();
02931   for (i = 0; i < count; ++i) {
02932     nsGlobalFont* globalFont = (nsGlobalFont*)gGlobalFonts->ElementAt(i);
02933     if (!globalFont->ccmap || 
02934         globalFont->flags & NS_GLOBALFONT_SKIP ||
02935         globalFont->fonttype != eFontType_Unicode) {
02936       continue;
02937     }
02938     if (CCMAP_HAS_CHAR(globalFont->ccmap, NS_REPLACEMENT_CHAR)) {
02939       nsFontWin* font = LoadSubstituteFont(aDC, globalFont->name);
02940       if (font) {
02941         ((nsFontWinSubstitute*)font)->SetRepresentable(c);
02942         mSubstituteFont = font;
02943         return font;
02944       }
02945     }
02946   }
02947   // We are running out of resources if we reach here... Try a stock font
02948   NS_ASSERTION(::GetMapMode(aDC) == MM_TEXT, "mapping mode needs to be MM_TEXT");
02949   nsFontWin* font = LoadSubstituteFont(aDC, EmptyString());
02950   if (font) {
02951     ((nsFontWinSubstitute*)font)->SetRepresentable(c);
02952     mSubstituteFont = font;
02953     return font;
02954   }
02955 
02956   NS_ERROR("Could not provide a substititute font");
02957   return nsnull;
02958 }
02959 
02960 nsFontWin*
02961 nsFontMetricsWin::LoadSubstituteFont(HDC aDC, const nsString& aName)
02962 {
02963   LOGFONT logFont;
02964   HFONT hfont = !aName.IsEmpty()
02965     ? CreateFontHandle(aDC, aName, &logFont)
02966     : (HFONT)::GetStockObject(SYSTEM_FONT);
02967   if (hfont) {
02968     // XXX 'displayUnicode' has to be initialized based on the desired rendering mode
02969     PRBool displayUnicode = PR_FALSE;
02970     /* substitute font does not need ccmap */
02971     LOGFONT* lfont = !aName.IsEmpty() ? &logFont : nsnull;
02972     nsFontWinSubstitute* font = new nsFontWinSubstitute(lfont, hfont, nsnull, displayUnicode);
02973     if (font) {
02974       HFONT oldFont = (HFONT)::SelectObject(aDC, (HGDIOBJ)hfont);
02975       InitMetricsFor(aDC, font);
02976       mLoadedFonts.AppendElement((nsFontWin*)font);
02977       ::SelectObject(aDC, (HGDIOBJ)oldFont);
02978       return font;
02979     }
02980     ::DeleteObject((HGDIOBJ)hfont);
02981   }
02982   return nsnull;
02983 }
02984 
02985 //------------ Font weight utilities -------------------
02986 
02987 // XXX: Should not need to store all these in a hash table.
02988 // We need to restructure the font management code so there is one
02989 // global place to cache font info. As the code is right now, there
02990 // are two separate places that font info is stored, in the gFamilyNames
02991 // hash table and the global font array. There are also cases where the
02992 // font info is not cached at all. 
02993 // I initially tried to add the font weight info to those two places, but
02994 // it was messy. In addition I discovered another code path which does not
02995 // cache anything. 
02996 
02997 // Entry for storing hash table. Store as a single
02998 // entry rather than doing a separate allocation for the
02999 // fontName and weight.
03000 
03001 class nsFontWeightEntry : public PLHashEntry
03002 {
03003 public:
03004   nsString mFontName;
03005   PRUint16 mWeightTable; // Each bit indicates the availability of a font weight.
03006 };
03007 
03008 static PLHashNumber
03009 HashKeyFontWeight(const void* aFontWeightEntry)
03010 {
03011   const nsString* string = &((const nsFontWeightEntry*) aFontWeightEntry)->mFontName;
03012   return (PLHashNumber)nsCRT::HashCode(string->get());
03013 }
03014 
03015 static PRIntn
03016 CompareKeysFontWeight(const void* aFontWeightEntry1, const void* aFontWeightEntry2)
03017 {
03018   const nsString* str1 = &((const nsFontWeightEntry*) aFontWeightEntry1)->mFontName;
03019   const nsString* str2 = &((const nsFontWeightEntry*) aFontWeightEntry2)->mFontName;
03020   return nsCRT::strcmp(str1->get(), str2->get()) == 0;
03021 }
03022 
03023 /*-----------------------
03024 ** Hash table allocation
03025 **----------------------*/
03026 //-- Font weight
03027 PR_STATIC_CALLBACK(void*) fontweight_AllocTable(void *pool, size_t size)
03028 {
03029   return nsMemory::Alloc(size);
03030 }
03031 
03032 PR_STATIC_CALLBACK(void) fontweight_FreeTable(void *pool, void *item)
03033 {
03034   nsMemory::Free(item);
03035 }
03036 
03037 PR_STATIC_CALLBACK(PLHashEntry*) fontweight_AllocEntry(void *pool, const void *key)
03038 {
03039   return new nsFontWeightEntry;
03040 }
03041 
03042 PR_STATIC_CALLBACK(void) fontweight_FreeEntry(void *pool, PLHashEntry *he, PRUint32 flag)
03043 {
03044   if (flag == HT_FREE_ENTRY)  {
03045     nsFontWeightEntry *fontWeightEntry = NS_STATIC_CAST(nsFontWeightEntry *, he);
03046     delete fontWeightEntry;
03047   }
03048 }
03049 
03050 PLHashAllocOps fontweight_HashAllocOps = {
03051   fontweight_AllocTable, fontweight_FreeTable,
03052   fontweight_AllocEntry, fontweight_FreeEntry
03053 };
03054 
03055 // Store the font weight as a bit in the aWeightTable
03056 void nsFontMetricsWin::SetFontWeight(PRInt32 aWeight, PRUint16* aWeightTable) {
03057   NS_ASSERTION((aWeight >= 0) && (aWeight <= 9), "Invalid font weight passed");
03058   *aWeightTable |= 1 << (aWeight - 1);
03059 }
03060 
03061 // Check to see if a font weight is available within the font weight table
03062 PRBool nsFontMetricsWin::IsFontWeightAvailable(PRInt32 aWeight, PRUint16 aWeightTable) {
03063   PRInt32 normalizedWeight = aWeight / 100;
03064   NS_ASSERTION((aWeight >= 100) && (aWeight <= 900), "Invalid font weight passed");
03065   PRUint16 bitwiseWeight = 1 << (normalizedWeight - 1);
03066   return (bitwiseWeight & aWeightTable) != 0;
03067 }
03068 
03069 typedef struct {
03070   LOGFONT  mLogFont;
03071   PRUint16 mWeights;
03072   int      mFontCount;
03073 } nsFontWeightInfo;
03074 
03075 static int CALLBACK
03076 nsFontWeightCallback(const LOGFONT* logFont, const TEXTMETRIC * metrics,
03077                      DWORD fontType, LPARAM closure)
03078 {
03079 // printf("Name %s Log font sizes %d\n",logFont->lfFaceName,logFont->lfWeight);
03080   nsFontWeightInfo* weightInfo = (nsFontWeightInfo*)closure;
03081   if (metrics) {
03082       // Set a bit to indicate the font weight is available
03083     if (weightInfo->mFontCount == 0)
03084       weightInfo->mLogFont = *logFont;
03085     nsFontMetricsWin::SetFontWeight(metrics->tmWeight / 100,
03086       &weightInfo->mWeights);
03087     ++weightInfo->mFontCount;
03088   }
03089   return TRUE; // Keep looking for more weights.
03090 }
03091 
03092 static void
03093 SearchSimulatedFontWeight(HDC aDC, nsFontWeightInfo* aWeightInfo)
03094 {
03095   int weight, weightCount;
03096 
03097   // if the font does not exist return immediately 
03098   if (aWeightInfo->mFontCount == 0) {
03099     return;
03100   }
03101 
03102   // If two or more nonsimulated variants exist, just use them.
03103   weightCount = 0;
03104   for (weight = 100; weight <= 900; weight += 100) {
03105     if (nsFontMetricsWin::IsFontWeightAvailable(weight, aWeightInfo->mWeights))
03106       ++weightCount;
03107   }
03108 
03109   // If the font does not exist (weightCount == 0) or
03110   // there are 2 or more weights already, don't look for
03111   // simulated font weights.
03112   if ((weightCount == 0) || (weightCount > 1)) {
03113     return;
03114   }
03115 
03116   // Searching simulated variants.
03117   // The tmWeight member holds simulated font weight.
03118   LOGFONT logFont = aWeightInfo->mLogFont;
03119   for (weight = 100; weight <= 900; weight += 100) {
03120     logFont.lfWeight = weight;
03121     HFONT hfont = ::CreateFontIndirect(&logFont);
03122     HFONT oldfont = (HFONT)::SelectObject(aDC, (HGDIOBJ)hfont);
03123 
03124     TEXTMETRIC metrics;
03125     GetTextMetrics(aDC, &metrics);
03126     if (metrics.tmWeight == weight) {
03127 //      printf("font weight for %s found: %d%s\n", logFont.lfFaceName, weight,
03128 //        nsFontMetricsWin::IsFontWeightAvailable(weight, aWeightInfo->mWeights) ?
03129 //        "" : " (simulated)");
03130       nsFontMetricsWin::SetFontWeight(weight / 100, &aWeightInfo->mWeights);
03131     }
03132 
03133     ::SelectObject(aDC, (HGDIOBJ)oldfont);
03134     ::DeleteObject((HGDIOBJ)hfont);
03135   }
03136 }
03137 
03138 PRUint16 
03139 nsFontMetricsWin::GetFontWeightTable(HDC aDC, const nsString& aFontName)
03140 {
03141   // Look for all of the weights for a given font.
03142   LOGFONT logFont;
03143   logFont.lfCharSet = DEFAULT_CHARSET;
03144 
03145   // The risk of losing characters not covered by the current codepage 
03146   // is reduced because LookupWinFontName invoked earlier has taken care 
03147   // of most cases. 
03148   WideCharToMultiByte(CP_ACP, 0, aFontName.get(), aFontName.Length() + 1,
03149                       logFont.lfFaceName, sizeof(logFont.lfFaceName),
03150                       nsnull, nsnull);
03151 
03152   logFont.lfPitchAndFamily = 0;
03153 
03154   nsFontWeightInfo weightInfo;
03155   weightInfo.mWeights = 0;
03156   weightInfo.mFontCount = 0;
03157   ::EnumFontFamiliesEx(aDC, &logFont, nsFontWeightCallback, (LPARAM)&weightInfo, 0);
03158   if (weightInfo.mFontCount == 0)
03159     ::EnumFontFamilies(aDC, logFont.lfFaceName, nsFontWeightCallback, (LPARAM)&weightInfo);
03160   SearchSimulatedFontWeight(aDC, &weightInfo);
03161 //  printf("font weights for %s dec %d hex %x \n", logFont.lfFaceName, weightInfo.mWeights, weightInfo.mWeights);
03162   return weightInfo.mWeights;
03163 }
03164 
03165 // Calculate the closest font weight. This is necessary because we need to
03166 // control the mapping of logical font weight to available weight to handle both CSS2
03167 // default algorithm + the case where a font weight is choosen which is not available then made
03168 // bolder or lighter. (e.g. a font weight of 200 is choosen but not available
03169 // on the system so a weight of 400 is used instead when mapping to a physical font.
03170 // If the font is made bolder we need to know that a font weight of 400 was choosen, so
03171 // we can select a font weight which is greater. 
03172 PRInt32
03173 nsFontMetricsWin::GetClosestWeight(PRInt32 aWeight, PRUint16 aWeightTable)
03174 {
03175   // Algorithm used From CSS2 section 15.5.1 Mapping font weight values to font names
03176 
03177   // Check for exact match
03178   if ((aWeight > 0) && IsFontWeightAvailable(aWeight, aWeightTable)) {
03179     return aWeight;
03180   }
03181 
03182   // Find lighter and darker weights to be used later.
03183 
03184   // First look for lighter
03185   PRBool done = PR_FALSE;
03186   PRInt32 lighterWeight = 0;
03187   PRInt32 proposedLighterWeight = PR_MAX(0, aWeight - 100);
03188   while (!done && (proposedLighterWeight >= 100)) {
03189     if (IsFontWeightAvailable(proposedLighterWeight, aWeightTable)) {
03190       lighterWeight = proposedLighterWeight;
03191       done = PR_TRUE;
03192     } else {
03193       proposedLighterWeight -= 100;
03194     }
03195   }
03196 
03197   // Now look for darker
03198   done = PR_FALSE;
03199   PRInt32 darkerWeight = 0;
03200   PRInt32 proposedDarkerWeight = PR_MIN(aWeight + 100, 900);
03201   while (!done && (proposedDarkerWeight <= 900)) {
03202     if (IsFontWeightAvailable(proposedDarkerWeight, aWeightTable)) {
03203       darkerWeight = proposedDarkerWeight;
03204       done = PR_TRUE;   
03205     } else {
03206       proposedDarkerWeight += 100;
03207     }
03208   }
03209 
03210   // From CSS2 section 15.5.1 
03211 
03212   // If '500' is unassigned, it will be
03213   // assigned the same font as '400'.
03214   // If any of '300', '200', or '100' remains unassigned, it is
03215   // assigned to the next lighter assigned keyword, if any, or 
03216   // the next darker otherwise. 
03217   // What about if the desired  weight is 500 and 400 is unassigned?.
03218   // This is not inlcluded in the CSS spec so I'll treat it in a consistent
03219   // manner with unassigned '300', '200' and '100'
03220 
03221   if (aWeight <= 500) {
03222     return lighterWeight ? lighterWeight : darkerWeight;
03223   } 
03224 
03225   // Automatically chose the bolder weight if the next lighter weight
03226   // makes it normal. (i.e goes over the normal to bold threshold.)
03227 
03228   // From CSS2 section 15.5.1 
03229   // if any of the values '600', '700', '800', or '900' remains unassigned, 
03230   // they are assigned to the same face as the next darker assigned keyword, 
03231   // if any, or the next lighter one otherwise.
03232   return darkerWeight ? darkerWeight : lighterWeight;
03233 }
03234 
03235 PRInt32
03236 nsFontMetricsWin::GetBolderWeight(PRInt32 aWeight, PRInt32 aDistance, PRUint16 aWeightTable)
03237 {
03238   PRInt32 newWeight = aWeight;
03239   PRInt32 proposedWeight = aWeight + 100; // Start 1 bolder than the current
03240   for (PRInt32 j = 0; j < aDistance; ++j) {
03241     PRBool foundWeight = PR_FALSE;
03242     while (!foundWeight && (proposedWeight <= NS_MAX_FONT_WEIGHT)) {
03243       if (IsFontWeightAvailable(proposedWeight, aWeightTable)) {
03244         newWeight = proposedWeight; 
03245         foundWeight = PR_TRUE;
03246       }
03247       proposedWeight += 100; 
03248     }
03249   }
03250   return newWeight;
03251 }
03252 
03253 PRInt32
03254 nsFontMetricsWin::GetLighterWeight(PRInt32 aWeight, PRInt32 aDistance, PRUint16 aWeightTable)
03255 {
03256   PRInt32 newWeight = aWeight;
03257   PRInt32 proposedWeight = aWeight - 100; // Start 1 lighter than the current
03258   for (PRInt32 j = 0; j < aDistance; ++j) {
03259     PRBool foundWeight = PR_FALSE;
03260     while (!foundWeight && (proposedWeight >= NS_MIN_FONT_WEIGHT)) {
03261       if (IsFontWeightAvailable(proposedWeight, aWeightTable)) {
03262         newWeight = proposedWeight; 
03263         foundWeight = PR_TRUE;
03264       }
03265       proposedWeight -= 100; 
03266     }
03267   }
03268   return newWeight;
03269 }
03270 
03271 PRInt32
03272 nsFontMetricsWin::GetFontWeight(PRInt32 aWeight, PRUint16 aWeightTable)
03273 {
03274   // The remainder is used to determine whether to make
03275   // the font lighter or bolder
03276   PRInt32 remainder = aWeight % 100;
03277   PRInt32 normalizedWeight = aWeight / 100;
03278   PRInt32 selectedWeight = 0;
03279 
03280   // No remainder, so get the closest weight
03281   if (remainder == 0) {
03282     selectedWeight = GetClosestWeight(aWeight, aWeightTable);
03283   } else {
03284     NS_ASSERTION((remainder < 10) || (remainder > 90), "Invalid bolder or lighter value");
03285     if (remainder < 10) {
03286       PRInt32 weight = GetClosestWeight(normalizedWeight * 100, aWeightTable);
03287       selectedWeight = GetBolderWeight(weight, remainder, aWeightTable);
03288     } else {
03289       // Have to add back 1 for the lighter weight since aWeight really refers to the 
03290       // whole number. eq. 398 really means 2 lighter than font weight 400.
03291       PRInt32 weight = GetClosestWeight((normalizedWeight + 1) * 100, aWeightTable);
03292       selectedWeight = GetLighterWeight(weight, 100-remainder, aWeightTable);
03293     }
03294   }
03295 
03296 //  printf("XXX Input weight %d output weight %d weight table hex %x\n", aWeight, selectedWeight, aWeightTable);
03297   return selectedWeight;
03298 }
03299 
03300 PRUint16
03301 nsFontMetricsWin::LookForFontWeightTable(HDC aDC, const nsString& aName)
03302 {
03303   // Initialize the font weight table if need be.
03304   if (!gFontWeights) {
03305     gFontWeights = PL_NewHashTable(0, HashKeyFontWeight, CompareKeysFontWeight, nsnull, &fontweight_HashAllocOps,
03306       nsnull);
03307     if (!gFontWeights) {
03308       return 0;
03309     }
03310   }
03311 
03312   // Use lower case name for hash table searches. This eliminates
03313   // keeping multiple font weights entries when the font name varies 
03314   // only by case.
03315   nsAutoString low(aName);
03316   ToLowerCase(low);
03317 
03318    // See if the font weight has already been computed.
03319   nsFontWeightEntry searchEntry;
03320   searchEntry.mFontName = low;
03321   searchEntry.mWeightTable = 0;
03322 
03323   nsFontWeightEntry* weightEntry;
03324   PLHashEntry **hep, *he;
03325   PLHashNumber hash = HashKeyFontWeight(&searchEntry);
03326   hep = PL_HashTableRawLookup(gFontWeights, hash, &searchEntry);
03327   he = *hep;
03328   if (he) {
03329     // an identical fontweight has already been added
03330     weightEntry = NS_STATIC_CAST(nsFontWeightEntry *, he);
03331     return weightEntry->mWeightTable;
03332   }
03333 
03334    // Hasn't been computed, so need to compute and store it.
03335   PRUint16 weightTable = GetFontWeightTable(aDC, aName);
03336 //  printf("Compute font weight %d\n",  weightTable);
03337 
03338    // Store it in font weight HashTable.
03339   he = PL_HashTableRawAdd(gFontWeights, hep, hash, &searchEntry, nsnull);
03340   if (he) {   
03341     weightEntry = NS_STATIC_CAST(nsFontWeightEntry*, he);
03342     weightEntry->mFontName = low;
03343     weightEntry->mWeightTable = weightTable;
03344     he->key = weightEntry;
03345     he->value = weightEntry;
03346     return weightEntry->mWeightTable;
03347   }
03348 
03349   return 0;
03350 }
03351 
03352 // ------------ End of font weight utilities
03353 
03354 nsFontWin*
03355 nsFontMetricsWin::FindUserDefinedFont(HDC aDC, PRUint32 aChar)
03356 {
03357   if (mIsUserDefined) {
03358     // the user-defined font is always loaded as the first font
03359     nsFontWin* font = LoadFont(aDC, mUserDefined);
03360     mIsUserDefined = PR_FALSE;
03361     if (font && font->HasGlyph(aChar))
03362       return font;    
03363   }
03364   return nsnull;
03365 }
03366 
03367 nsFontWin*
03368 nsFontMetricsWin::FindLocalFont(HDC aDC, PRUint32 aChar)
03369 {
03370   while (mFontsIndex < mFonts.Count()) {
03371     if (mFontsIndex == mGenericIndex) {
03372       return nsnull;
03373     }
03374 
03375     nsString* name = mFonts.StringAt(mFontsIndex++);
03376     nsAutoString winName; 
03377     PRBool found = LookupWinFontName(*name, winName); 
03378     // the familyNameQuirks should not affect generic & global fonts
03379     nsFontWin* font = LoadFont(aDC, found ? winName : *name,
03380                                mFont.familyNameQuirks);
03381     if (font && font->HasGlyph(aChar)) {
03382       return font;
03383     }
03384   }
03385   return nsnull;
03386 }
03387 
03388 nsFontWin*
03389 nsFontMetricsWin::LoadGenericFont(HDC aDC, PRUint32 aChar, const nsString& aName)
03390 {
03391   for (int i = mLoadedFonts.Count()-1; i >= 0; --i) {
03392     // woah, this seems bad
03393     const nsACString& fontName =
03394       nsDependentCString(((nsFontWin*)mLoadedFonts[i])->mName);
03395     if (aName.Equals(NS_ConvertASCIItoUCS2(fontName),
03396                      nsCaseInsensitiveStringComparator()))
03397       return nsnull;
03398 
03399   }
03400   nsFontWin* font = LoadFont(aDC, aName);
03401   if (font && font->HasGlyph(aChar)) {
03402     return font;
03403   }
03404   return nsnull;
03405 }
03406 
03407 struct GenericFontEnumContext
03408 {
03409   HDC               mDC;
03410   PRUint32          mChar;
03411   nsFontWin*        mFont;
03412   nsFontMetricsWin* mMetrics;
03413 };
03414 
03415 static PRBool PR_CALLBACK
03416 GenericFontEnumCallback(const nsString& aFamily, PRBool aGeneric, void* aData)
03417 {
03418   GenericFontEnumContext* context = (GenericFontEnumContext*)aData;
03419   HDC dc = context->mDC;
03420   PRUint32 ch = context->mChar;
03421   nsFontMetricsWin* metrics = context->mMetrics;
03422   context->mFont = metrics->LoadGenericFont(dc, ch, aFamily);
03423   if (context->mFont) {
03424     return PR_FALSE; // stop enumerating the list
03425   }
03426   return PR_TRUE; // don't stop
03427 }
03428 
03429 #define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
03430  _pref.Assign(_s0); \
03431  _pref.Append(_s1);
03432 
03433 static void 
03434 AppendGenericFontFromPref(nsString& aFontname,
03435                           const char* aLangGroup,
03436                           const char* aGeneric)
03437 {
03438   nsresult res;
03439   nsCAutoString pref;
03440   nsXPIDLString value;
03441   nsCAutoString generic_dot_langGroup;
03442 
03443   generic_dot_langGroup.Assign(aGeneric);
03444   generic_dot_langGroup.Append('.');
03445   generic_dot_langGroup.Append(aLangGroup);
03446 
03447   // font.name.[generic].[langGroup]
03448   // the current user' selected font, it gives the first preferred font
03449   MAKE_FONT_PREF_KEY(pref, "font.name.", generic_dot_langGroup);
03450   res = gPref->CopyUnicharPref(pref.get(), getter_Copies(value));      
03451   if (NS_SUCCEEDED(res)) {
03452     if(!aFontname.IsEmpty())
03453       aFontname.Append((PRUnichar)',');
03454     aFontname.Append(value);
03455   }
03456 
03457   // font.name-list.[generic].[langGroup]
03458   // the pre-built list of default fonts, it gives alternative fonts
03459   MAKE_FONT_PREF_KEY(pref, "font.name-list.", generic_dot_langGroup);
03460   res = gPref->CopyUnicharPref(pref.get(), getter_Copies(value));      
03461   if (NS_SUCCEEDED(res)) {
03462     if(!aFontname.IsEmpty())
03463       aFontname.Append((PRUnichar)',');
03464     aFontname.Append(value);
03465   }
03466 }
03467 
03468 nsFontWin*
03469 nsFontMetricsWin::FindGenericFont(HDC aDC, PRUint32 aChar)
03470 {
03471   if (mTriedAllGenerics) {
03472     // don't bother anymore because mLoadedFonts[] already has all our generic fonts
03473     return nsnull;
03474   }
03475 
03476   // This is a nifty hook that we will use to just iterate over
03477   // the list of names using the callback mechanism of nsFont...
03478   nsFont font("", 0, 0, 0, 0, 0);
03479 
03480   if (mLangGroup) {
03481     const char* langGroup;
03482     mLangGroup->GetUTF8String(&langGroup);
03483   
03484     // x-unicode pseudo-langGroup should be the last resort to turn to.
03485     // That is, it should be refered to only when we don't  recognize 
03486     // |langGroup| specified by the authors of documents and  the 
03487     // determination of |langGroup| based  on Unicode range also fails 
03488     // in |FindPrefFont|. 
03489 
03490     if (!strcmp(langGroup, "x-unicode")) {
03491       mTriedAllGenerics = 1;
03492       return nsnull;
03493     }
03494 
03495     AppendGenericFontFromPref(font.name, langGroup, 
03496                               NS_ConvertUCS2toUTF8(mGeneric).get());
03497   }
03498 
03499   // Iterate over the list of names using the callback mechanism of nsFont...
03500   GenericFontEnumContext context = {aDC, aChar, nsnull, this};
03501   font.EnumerateFamilies(GenericFontEnumCallback, &context);
03502   if (context.mFont) { // a suitable font was found
03503     return context.mFont;
03504   }
03505 
03506 #if defined(DEBUG_rbs) || defined(DEBUG_shanjian)
03507   const char* lang;
03508   mLangGroup->GetUTF8String(&lang);
03509   NS_ConvertUCS2toUTF8 generic(mGeneric);
03510   NS_ConvertUCS2toUTF8 family(mFont.name);
03511   printf("FindGenericFont missed:U+%04X langGroup:%s generic:%s mFont.name:%s\n", 
03512          aChar, lang, generic.get(), family.get());
03513 #endif
03514 
03515   mTriedAllGenerics = 1;
03516   return nsnull;
03517 }
03518 
03519 #define IsCJKLangGroupAtom(a)  ((a)==gJA || (a)==gKO || (a)==gZHCN || \
03520                                 (a)==gZHTW || (a) == gZHHK)
03521 
03522 nsFontWin*
03523 nsFontMetricsWin::FindPrefFont(HDC aDC, PRUint32 aChar)
03524 {
03525   if (mTriedAllPref) {
03526     // don't bother anymore because mLoadedFonts[] already has all our pref fonts
03527     return nsnull;
03528   }
03529   nsFont font("", 0, 0, 0, 0, 0);
03530 
03531   // Sometimes we could not find the font in doc's suggested langGroup,(this usually means  
03532   // the language specified by doc is incorrect). The characters can, to a certain degree, 
03533   // tell us what language it is. This allows us to quickly locate and use a more appropriate 
03534   // font as indicated by user's preference. In some situations a set of possible languages may
03535   // be identified instead of a single language (eg. CJK and latin). In this case we have to 
03536   // try every language in the set. gUserLocale and gSystemLocale provide some hints about 
03537   // which one should be tried first. This is important for CJK font, since the glyph for single 
03538   // char varies dramatically in different langauges. For latin languages, their glyphs are 
03539   // similar. In fact, they almost always share identical fonts. It will be a waste of time to 
03540   // figure out which one comes first. As a final fallback, unicode preference is always tried. 
03541 
03542   PRUint32 unicodeRange = FindCharUnicodeRange(aChar);
03543   if (unicodeRange < kRangeSpecificItemNum) {
03544     // a single language is identified
03545     AppendGenericFontFromPref(font.name, LangGroupFromUnicodeRange(unicodeRange), 
03546                               NS_ConvertUCS2toUTF8(mGeneric).get());
03547   } else if (kRangeSetLatin == unicodeRange) { 
03548     // Character is from a latin language set, so try western and central european
03549     // If mLangGroup is western or central european, this most probably will not be
03550     // used, but is here as a fallback scenario.    
03551     AppendGenericFontFromPref(font.name, "x-western",
03552                               NS_ConvertUCS2toUTF8(mGeneric).get());
03553     AppendGenericFontFromPref(font.name, "x-central-euro",
03554                               NS_ConvertUCS2toUTF8(mGeneric).get());
03555   } else if (kRangeSetCJK == unicodeRange) { 
03556     // CJK, we have to be careful about the order, use locale info as hint
03557     
03558     // then try user locale first, if it is CJK
03559     if ((gUsersLocale != mLangGroup) && IsCJKLangGroupAtom(gUsersLocale)) {
03560       nsCAutoString usersLocaleLangGroup;
03561       gUsersLocale->ToUTF8String(usersLocaleLangGroup);
03562       AppendGenericFontFromPref(font.name, usersLocaleLangGroup.get(), 
03563                                 NS_ConvertUCS2toUTF8(mGeneric).get());
03564     }
03565     
03566     // then system locale (os language)
03567     if ((gSystemLocale != mLangGroup) && (gSystemLocale != gUsersLocale) && IsCJKLangGroupAtom(gSystemLocale)) {
03568       nsCAutoString systemLocaleLangGroup;
03569       gSystemLocale->ToUTF8String(systemLocaleLangGroup);
03570       AppendGenericFontFromPref(font.name, systemLocaleLangGroup.get(), 
03571                                 NS_ConvertUCS2toUTF8(mGeneric).get());
03572     }
03573 
03574     // try all other languages in this set.
03575     if (mLangGroup != gJA && gUsersLocale != gJA && gSystemLocale != gJA)
03576       AppendGenericFontFromPref(font.name, "ja",
03577                                 NS_ConvertUCS2toUTF8(mGeneric).get());
03578     if (mLangGroup != gZHCN && gUsersLocale != gZHCN && gSystemLocale != gZHCN)
03579       AppendGenericFontFromPref(font.name, "zh-CN",
03580                                 NS_ConvertUCS2toUTF8(mGeneric).get());
03581     if (mLangGroup != gZHTW && gUsersLocale != gZHTW && gSystemLocale != gZHTW)
03582       AppendGenericFontFromPref(font.name, "zh-TW",
03583                                 NS_ConvertUCS2toUTF8(mGeneric).get());
03584     if (mLangGroup != gZHHK && gUsersLocale != gZHHK && gSystemLocale != gZHHK)
03585       AppendGenericFontFromPref(font.name, "zh-HK",
03586                                 NS_ConvertUCS2toUTF8(mGeneric).get());
03587     if (mLangGroup != gKO && gUsersLocale != gKO && gSystemLocale != gKO)
03588       AppendGenericFontFromPref(font.name, "ko",
03589                                 NS_ConvertUCS2toUTF8(mGeneric).get());
03590   } 
03591 
03592   // always try unicode as fallback
03593   AppendGenericFontFromPref(font.name, "x-unicode",
03594                             NS_ConvertUCS2toUTF8(mGeneric).get());
03595   
03596   // use the font list to find font
03597   GenericFontEnumContext context = {aDC, aChar, nsnull, this};
03598   font.EnumerateFamilies(GenericFontEnumCallback, &context);
03599   if (context.mFont) { // a suitable font was found
03600     return context.mFont;
03601   }
03602   mTriedAllPref = 1;
03603   return nsnull;
03604 }
03605 
03606 nsFontWin*
03607 nsFontMetricsWin::FindFont(HDC aDC, PRUint32 aChar)
03608 {
03609 #ifdef DEBUG_emk
03610   LARGE_INTEGER start, end;
03611   QueryPerformanceFrequency(&freq);
03612   QueryPerformanceCounter(&start);
03613 #endif
03614   // the first font should be for invisible ignorable characters
03615   if (mLoadedFonts.Count() < 1)
03616     mLoadedFonts.AppendElement(gFontForIgnorable);
03617   if (gFontForIgnorable->HasGlyph(aChar))
03618       return gFontForIgnorable;
03619 
03620   nsFontWin* font = FindUserDefinedFont(aDC, aChar);
03621   if (!font) {
03622     font = FindLocalFont(aDC, aChar);
03623     if (!font) {
03624       font = FindGenericFont(aDC, aChar);
03625       if (!font) {
03626         font = FindPrefFont(aDC, aChar);
03627         if (!font) {
03628 #ifdef DEBUG_emk
03629           QueryPerformanceCounter(&prev);
03630 #endif
03631           font = FindGlobalFont(aDC, aChar);
03632           if (!font) {
03633 #ifdef DEBUG_emk
03634             QueryPerformanceCounter(&end);
03635             printf("%g sec.\n", (end.QuadPart - start.QuadPart) / (double)freq.QuadPart);
03636 #endif
03637             font = FindSubstituteFont(aDC, aChar);
03638           }
03639         }
03640       }
03641     }
03642   }
03643   return font;
03644 }
03645 
03646 nsFontWin*
03647 nsFontMetricsWin::GetFontFor(HFONT aHFONT)
03648 {
03649   int count = mLoadedFonts.Count();
03650   for (int i = 0; i < count; ++i) {
03651     nsFontWin* font = (nsFontWin*)mLoadedFonts[i];
03652     if (font->mFont == aHFONT)
03653       return font;
03654   }
03655   NS_ERROR("Cannot find the font that owns the handle");
03656   return nsnull;
03657 }
03658 
03659 static PRBool
03660 FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
03661 {
03662   nsFontMetricsWin* metrics = (nsFontMetricsWin*) aData;
03663   metrics->mFonts.AppendString(aFamily);
03664   if (aGeneric) {
03665     metrics->mGeneric.Assign(aFamily);
03666     ToLowerCase(metrics->mGeneric);
03667     return PR_FALSE; // stop
03668   }
03669   ++metrics->mGenericIndex;
03670 
03671   return PR_TRUE; // don't stop
03672 }
03673 
03679 nsresult
03680 nsFontMetricsWin::RealizeFont()
03681 {
03682   nsresult rv;
03683   HWND win = NULL;
03684   HDC  dc = NULL;
03685   HDC  dc1 = NULL;
03686 
03687   if (mDeviceContext->mDC){
03688     // XXX - DC If we are printing, we need to get the printer HDC and a screen HDC
03689     // The screen HDC is because there seems to be a bug or requirment that the 
03690     // GetFontData() method call have a screen HDC, some printers HDC's return nothing
03691     // thats will give us bad font data, and break us.  
03692     dc = mDeviceContext->mDC;
03693     win = (HWND)mDeviceContext->mWidget;
03694     dc1 = ::GetDC(win);
03695   } else {
03696     // Find font metrics and character widths
03697     win = (HWND)mDeviceContext->mWidget;
03698     dc = ::GetDC(win);
03699     dc1 = dc;
03700   }
03701 
03702   mFont.EnumerateFamilies(FontEnumCallback, this); 
03703 
03704   nsCAutoString pref;
03705   nsXPIDLString value;
03706 
03707   // set a fallback generic font if the font-family list didn't have one
03708   if (mGeneric.IsEmpty()) {
03709     pref.Assign("font.default.");
03710     const char* langGroup;
03711     mLangGroup->GetUTF8String(&langGroup);
03712     pref.Append(langGroup);
03713     rv = gPref->CopyUnicharPref(pref.get(), getter_Copies(value));
03714     if (NS_SUCCEEDED(rv)) {
03715       mGeneric.Assign(value);
03716     }
03717     else {
03718       mGeneric.AssignLiteral("serif");
03719     }
03720   }
03721 
03722   if (mLangGroup.get() == gUserDefined) {
03723     if (!gUserDefinedConverter) {
03724       rv = gCharsetManager->GetUnicodeEncoderRaw("x-user-defined", &gUserDefinedConverter);
03725       if (NS_FAILED(rv)) return rv;
03726       gUserDefinedConverter->SetOutputErrorBehavior(
03727         gUserDefinedConverter->kOnError_Replace, nsnull, '?');
03728       nsCOMPtr<nsICharRepresentable> mapper =
03729         do_QueryInterface(gUserDefinedConverter);
03730       if (mapper) {
03731         gUserDefinedCCMap = MapperToCCMap(mapper);
03732       }
03733     }
03734 
03735     // See if this is a special user-defined font encoding by checking:
03736     // font.name.[generic].x-user-def
03737     pref.Assign("font.name.");
03738     pref.AppendWithConversion(mGeneric);
03739     pref.Append(".x-user-def");
03740     rv = gPref->CopyUnicharPref(pref.get(), getter_Copies(value));
03741     if (NS_SUCCEEDED(rv)) {
03742       mUserDefined.Assign(value);
03743       mIsUserDefined = 1;
03744     }
03745   }
03746 
03747   nsFontWin* font = FindFont(dc1, 'a');
03748   NS_ASSERTION(font, "missing font");
03749   if (!font) {
03750     ::ReleaseDC(win, mDeviceContext->mDC ? dc1 : dc);
03751     return NS_ERROR_FAILURE;
03752   }
03753   mFontHandle = font->mFont;
03754 
03755   HFONT oldfont = (HFONT)::SelectObject(dc, (HGDIOBJ) mFontHandle);
03756 
03757   // Get font metrics
03758   float dev2app;
03759   dev2app = mDeviceContext->DevUnitsToAppUnits();
03760   OUTLINETEXTMETRIC oMetrics;
03761   TEXTMETRIC& metrics = oMetrics.otmTextMetrics;
03762   nscoord onePixel = NSToCoordRound(1 * dev2app);
03763   nscoord descentPos = 0;
03764 
03765   if (0 < ::GetOutlineTextMetrics(dc, sizeof(oMetrics), &oMetrics)) {
03766 //    mXHeight = NSToCoordRound(oMetrics.otmsXHeight * dev2app);  XXX not really supported on windows
03767     mXHeight = NSToCoordRound((float)metrics.tmAscent * dev2app * 0.56f); // 50% of ascent, best guess for true type
03768     mSuperscriptOffset = NSToCoordRound(oMetrics.otmptSuperscriptOffset.y * dev2app);
03769     mSubscriptOffset = NSToCoordRound(oMetrics.otmptSubscriptOffset.y * dev2app);
03770 
03771     mStrikeoutSize = PR_MAX(onePixel, NSToCoordRound(oMetrics.otmsStrikeoutSize * dev2app));
03772     mStrikeoutOffset = NSToCoordRound(oMetrics.otmsStrikeoutPosition * dev2app);
03773     mUnderlineSize = PR_MAX(onePixel, NSToCoordRound(oMetrics.otmsUnderscoreSize * dev2app));
03774     if (gDoingLineheightFixup) {
03775       if(IsCJKLangGroupAtom(mLangGroup.get())) {
03776         mUnderlineOffset = NSToCoordRound(PR_MIN(oMetrics.otmsUnderscorePosition, 
03777                                                  oMetrics.otmDescent + oMetrics.otmsUnderscoreSize) 
03778                                                  * dev2app);
03779         // keep descent position, use it for mUnderlineOffset if leading allows
03780         descentPos = NSToCoordRound(oMetrics.otmDescent * dev2app);
03781       } else {
03782         mUnderlineOffset = NSToCoordRound(PR_MIN(oMetrics.otmsUnderscorePosition*dev2app, 
03783                                                  oMetrics.otmDescent*dev2app + mUnderlineSize));
03784       }
03785     }
03786     else
03787       mUnderlineOffset = NSToCoordRound(oMetrics.otmsUnderscorePosition * dev2app);
03788 
03789     // Begin -- section of code to get the real x-height with GetGlyphOutline()
03790     GLYPHMETRICS gm;
03791     DWORD len = gGlyphAgent.GetGlyphMetrics(dc, PRUnichar('x'), 0, &gm);
03792     if (GDI_ERROR != len && gm.gmptGlyphOrigin.y > 0)
03793     {
03794       mXHeight = NSToCoordRound(gm.gmptGlyphOrigin.y * dev2app);
03795     }
03796     // End -- getting x-height
03797   }
03798   else {
03799     // Make a best-effort guess at extended metrics
03800     // this is based on general typographic guidelines
03801     ::GetTextMetrics(dc, &metrics);
03802     mXHeight = NSToCoordRound((float)metrics.tmAscent * dev2app * 0.56f); // 56% of ascent, best guess for non-true type
03803     mSuperscriptOffset = mXHeight;     // XXX temporary code!
03804     mSubscriptOffset = mXHeight;     // XXX temporary code!
03805 
03806     mStrikeoutSize = onePixel; // XXX this is a guess
03807     mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0f); // 50% of xHeight
03808     mUnderlineSize = onePixel; // XXX this is a guess
03809     mUnderlineOffset = -NSToCoordRound((float)metrics.tmDescent * dev2app * 0.30f); // 30% of descent
03810   }
03811 
03812   mInternalLeading = NSToCoordRound(metrics.tmInternalLeading * dev2app);
03813   mExternalLeading = NSToCoordRound(metrics.tmExternalLeading * dev2app);
03814   mEmHeight = NSToCoordRound((metrics.tmHeight - metrics.tmInternalLeading) *
03815                              dev2app);
03816   mEmAscent = NSToCoordRound((metrics.tmAscent - metrics.tmInternalLeading) *
03817                              dev2app);
03818   mEmDescent = NSToCoordRound(metrics.tmDescent * dev2app);
03819   mMaxHeight = NSToCoordRound(metrics.tmHeight * dev2app);
03820   mMaxAscent = NSToCoordRound(metrics.tmAscent * dev2app);
03821   mMaxDescent = NSToCoordRound(metrics.tmDescent * dev2app);
03822   mMaxAdvance = NSToCoordRound(metrics.tmMaxCharWidth * dev2app);
03823   // Windows may screw up if we try to measure/draw more than 32767 pixels in
03824   // one operation.
03825   mMaxStringLength = (PRInt32)floor(32767.0/metrics.tmMaxCharWidth);
03826   mMaxStringLength = PR_MAX(1, mMaxStringLength);
03827 
03828   mAveCharWidth = PR_MAX(1, NSToCoordRound(metrics.tmAveCharWidth * dev2app));
03829 
03830   if (gDoingLineheightFixup) {
03831     if (mInternalLeading + mExternalLeading > mUnderlineSize &&
03832         descentPos < mUnderlineOffset) {
03833       // If underline positioned is too near from the text, descent position
03834       // is preferred, but we need to make sure there is enough space
03835       // available so that underline will stay within boundary.
03836       mUnderlineOffset = descentPos;
03837       nscoord extra = mUnderlineSize - mUnderlineOffset - mMaxDescent;
03838       if (extra > 0) {
03839         mEmDescent += extra;  
03840         mEmHeight += extra;
03841         mMaxDescent += extra;
03842         mMaxHeight += extra;
03843       }
03844     } else if (mUnderlineSize - mUnderlineOffset > mMaxDescent) {
03845       // If underline positioned is too far from the text, descent position
03846       // is preferred so that underline will stay within boundary.
03847       mUnderlineOffset = mUnderlineSize - mMaxDescent;
03848     }
03849   }
03850   // Cache the width of a single space.
03851   SIZE  size;
03852   ::GetTextExtentPoint32(dc, " ", 1, &size);
03853   size.cx -= font->mOverhangCorrection;
03854   mSpaceWidth = NSToCoordRound(size.cx * dev2app);
03855 
03856   ::SelectObject(dc, oldfont);
03857 
03858   ::ReleaseDC(win, mDeviceContext->mDC ? dc1 : dc);
03859   return NS_OK;
03860 }
03861 
03862 NS_IMETHODIMP
03863 nsFontMetricsWin::GetSpaceWidth(nscoord& aSpaceWidth)
03864 {
03865   aSpaceWidth = mSpaceWidth;
03866   return NS_OK;
03867 }
03868 
03869 NS_IMETHODIMP
03870 nsFontMetricsWin::GetXHeight(nscoord& aResult)
03871 {
03872   aResult = mXHeight;
03873   return NS_OK;
03874 }
03875 
03876 NS_IMETHODIMP
03877 nsFontMetricsWin::GetSuperscriptOffset(nscoord& aResult)
03878 {
03879   aResult = mSuperscriptOffset;
03880   return NS_OK;
03881 }
03882 
03883 NS_IMETHODIMP
03884 nsFontMetricsWin::GetSubscriptOffset(nscoord& aResult)
03885 {
03886   aResult = mSubscriptOffset;
03887   return NS_OK;
03888 }
03889 
03890 NS_IMETHODIMP
03891 nsFontMetricsWin::GetStrikeout(nscoord& aOffset, nscoord& aSize)
03892 {
03893   aOffset = mStrikeoutOffset;
03894   aSize = mStrikeoutSize;
03895   return NS_OK;
03896 }
03897 
03898 NS_IMETHODIMP
03899 nsFontMetricsWin::GetUnderline(nscoord& aOffset, nscoord& aSize)
03900 {
03901   aOffset = mUnderlineOffset;
03902   aSize = mUnderlineSize;
03903   return NS_OK;
03904 }
03905 
03906 NS_IMETHODIMP
03907 nsFontMetricsWin::GetHeight(nscoord &aHeight)
03908 {
03909   aHeight = mMaxHeight;
03910   return NS_OK;
03911 }
03912 
03913 #ifdef FONT_LEADING_APIS_V2
03914 NS_IMETHODIMP
03915 nsFontMetricsWin::GetInternalLeading(nscoord &aLeading)
03916 {
03917   aLeading = mInternalLeading;
03918   return NS_OK;
03919 }
03920 
03921 NS_IMETHODIMP
03922 nsFontMetricsWin::GetExternalLeading(nscoord &aLeading)
03923 {
03924   aLeading = mExternalLeading;
03925   return NS_OK;
03926 }
03927 #else
03928 NS_IMETHODIMP
03929 nsFontMetricsWin::GetLeading(nscoord &aLeading)
03930 {
03931   aLeading = mInternalLeading;
03932   return NS_OK;
03933 }
03934 
03935 NS_IMETHODIMP
03936 nsFontMetricsWin::GetNormalLineHeight(nscoord &aHeight)
03937 {
03938   aHeight = mEmHeight + mInternalLeading;
03939   return NS_OK;
03940 }
03941 #endif //FONT_LEADING_APIS_V2
03942 
03943 NS_IMETHODIMP
03944 nsFontMetricsWin::GetEmHeight(nscoord &aHeight)
03945 {
03946   aHeight = mEmHeight;
03947   return NS_OK;
03948 }
03949 
03950 NS_IMETHODIMP
03951 nsFontMetricsWin::GetEmAscent(nscoord &aAscent)
03952 {
03953   aAscent = mEmAscent;
03954   return NS_OK;
03955 }
03956 
03957 NS_IMETHODIMP
03958 nsFontMetricsWin::GetEmDescent(nscoord &aDescent)
03959 {
03960   aDescent = mEmDescent;
03961   return NS_OK;
03962 }
03963 
03964 NS_IMETHODIMP
03965 nsFontMetricsWin::GetMaxHeight(nscoord &aHeight)
03966 {
03967   aHeight = mMaxHeight;
03968   return NS_OK;
03969 }
03970 
03971 NS_IMETHODIMP
03972 nsFontMetricsWin::GetMaxAscent(nscoord &aAscent)
03973 {
03974   aAscent = mMaxAscent;
03975   return NS_OK;
03976 }
03977 
03978 NS_IMETHODIMP
03979 nsFontMetricsWin::GetMaxDescent(nscoord &aDescent)
03980 {
03981   aDescent = mMaxDescent;
03982   return NS_OK;
03983 }
03984 
03985 NS_IMETHODIMP
03986 nsFontMetricsWin::GetMaxAdvance(nscoord &aAdvance)
03987 {
03988   aAdvance = mMaxAdvance;
03989   return NS_OK;
03990 }
03991 
03992 NS_IMETHODIMP
03993 nsFontMetricsWin::GetAveCharWidth(nscoord &aAveCharWidth)
03994 {
03995   aAveCharWidth = mAveCharWidth;
03996   return NS_OK;
03997 }
03998 
03999 PRInt32
04000 nsFontMetricsWin::GetMaxStringLength()
04001 {
04002   return mMaxStringLength;
04003 }
04004 
04005 NS_IMETHODIMP
04006 nsFontMetricsWin::GetLangGroup(nsIAtom** aLangGroup)
04007 {
04008   NS_ENSURE_ARG_POINTER(aLangGroup);
04009   *aLangGroup = mLangGroup;
04010   NS_IF_ADDREF(*aLangGroup);
04011   return NS_OK;
04012 }
04013 
04014 NS_IMETHODIMP
04015 nsFontMetricsWin::GetFontHandle(nsFontHandle &aHandle)
04016 {
04017   aHandle = mFontHandle;
04018   return NS_OK;
04019 }
04020 
04021 nsFontWin*
04022 nsFontMetricsWin::LocateFont(HDC aDC, PRUint32 aChar, PRInt32 & aCount)
04023 {
04024   nsFontWin *font;
04025   PRInt32 i;
04026 
04027   // see if one of our loaded fonts can represent the character
04028   for (i = 0; i < aCount; ++i) {
04029     font = (nsFontWin*)mLoadedFonts[i];
04030     if (font->HasGlyph(aChar))
04031       return font;
04032   }
04033 
04034   font = FindFont(aDC, aChar);
04035   aCount = mLoadedFonts.Count(); // update since FindFont() can change it
04036   NS_ASSERTION(font && mLoadedFonts.IndexOf(font) >= 0,
04037                "Could not find a font");
04038   return font;
04039 }
04040 
04041 nsresult
04042 nsFontMetricsWin::ResolveForwards(HDC                  aDC,
04043                                   const PRUnichar*     aString,
04044                                   PRUint32             aLength,
04045                                   nsFontSwitchCallback aFunc, 
04046                                   void*                aData)
04047 {
04048   NS_ASSERTION(aString || !aLength, "invalid call");
04049   const PRUnichar* firstChar = aString;
04050   const PRUnichar* currChar = firstChar;
04051   const PRUnichar* lastChar  = aString + aLength;
04052   nsFontWin* currFont;
04053   nsFontWin* nextFont;
04054   PRInt32 count;
04055   nsFontSwitch fontSwitch;
04056 
04057   if (firstChar == lastChar)
04058     return NS_OK;
04059 
04060   count = mLoadedFonts.Count();
04061 
04062   if (IS_HIGH_SURROGATE(*currChar) && (currChar+1) < lastChar && IS_LOW_SURROGATE(*(currChar+1))) {
04063     currFont = LocateFont(aDC, SURROGATE_TO_UCS4(*currChar, *(currChar+1)), count);
04064     currChar += 2;
04065   }
04066   else {
04067     currFont = LocateFont(aDC, *currChar, count);
04068     ++currChar;
04069   }
04070 
04071   //This if block is meant to speedup the process in normal situation, when
04072   //most characters can be found in first font
04073   NS_ASSERTION(count > 1, "only one font loaded");
04074   // mLoadedFont[0] == font for invisible ignorable characters
04075   PRUint32 firstFont = count > 1 ? 1 : 0; 
04076   if (currFont == mLoadedFonts[firstFont]) { 
04077     while (currChar < lastChar && 
04078            (currFont->HasGlyph(*currChar)) &&
04079            !CCMAP_HAS_CHAR_EXT(gIgnorableCCMapExt, *currChar))
04080       ++currChar;
04081     fontSwitch.mFontWin = currFont;
04082     if (!(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData))
04083       return NS_OK;
04084     if (currChar == lastChar)
04085       return NS_OK;
04086     // continue with the next substring, re-using the available loaded fonts
04087     firstChar = currChar;
04088     if (IS_HIGH_SURROGATE(*currChar) && (currChar+1) < lastChar && IS_LOW_SURROGATE(*(currChar+1))) {
04089       currFont = LocateFont(aDC, SURROGATE_TO_UCS4(*currChar, *(currChar+1)), count);
04090       currChar += 2;
04091     }
04092     else {
04093       currFont = LocateFont(aDC, *currChar, count);
04094       ++currChar;
04095     }
04096   }
04097 
04098   // see if we can keep the same font for adjacent characters
04099   PRInt32 lastCharLen;
04100   while (currChar < lastChar) {
04101     if (IS_HIGH_SURROGATE(*currChar) && (currChar+1) < lastChar && IS_LOW_SURROGATE(*(currChar+1))) {
04102       nextFont = LocateFont(aDC, SURROGATE_TO_UCS4(*currChar, *(currChar+1)), count);
04103       lastCharLen = 2;
04104     }
04105     else {
04106       nextFont = LocateFont(aDC, *currChar, count);
04107       lastCharLen = 1;
04108     }
04109     if (nextFont != currFont) {
04110       // We have a substring that can be represented with the same font, and
04111       // we are about to switch fonts, it is time to notify our caller.
04112       fontSwitch.mFontWin = currFont;
04113       if (!(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData))
04114         return NS_OK;
04115       // continue with the next substring, re-using the available loaded fonts
04116       firstChar = currChar;
04117 
04118       currFont = nextFont; // use the font found earlier for the char
04119     }
04120     currChar += lastCharLen;
04121   }
04122 
04123   //do it for last part of the string
04124   fontSwitch.mFontWin = currFont;
04125   (*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData);
04126   return NS_OK;
04127 }
04128 
04129 nsresult
04130 nsFontMetricsWin::ResolveBackwards(HDC                  aDC,
04131                                    const PRUnichar*     aString,
04132                                    PRUint32             aLength,
04133                                    nsFontSwitchCallback aFunc, 
04134                                    void*                aData)
04135 {
04136   NS_ASSERTION(aString || !aLength, "invalid call");
04137   const PRUnichar* firstChar = aString + aLength - 1;
04138   const PRUnichar* lastChar  = aString - 1;
04139   const PRUnichar* currChar  = firstChar;
04140   nsFontWin* currFont;
04141   nsFontWin* nextFont;
04142   PRInt32 count;
04143   nsFontSwitch fontSwitch;
04144 
04145   if (firstChar == lastChar)
04146     return NS_OK;
04147 
04148   count = mLoadedFonts.Count();
04149 
04150   // see if one of our loaded fonts can represent the current character
04151   if (IS_LOW_SURROGATE(*currChar) && (currChar-1) > lastChar && IS_HIGH_SURROGATE(*(currChar-1))) {
04152     currFont = LocateFont(aDC, SURROGATE_TO_UCS4(*(currChar-1), *currChar), count);
04153     currChar -= 2;
04154   }
04155   else {
04156     currFont = LocateFont(aDC, *currChar, count);
04157     --currChar;
04158   }
04159 
04160   //This if block is meant to speedup the process in normal situation, when
04161   //most characters can be found in first font
04162   NS_ASSERTION(count > 1, "only one font loaded");
04163   // mLoadedFont[0] == font for invisible ignorable characters
04164   PRUint32 firstFont = count > 1 ? 1 : 0; 
04165   if (currFont == mLoadedFonts[firstFont]) {
04166     while (currChar > lastChar && 
04167            (currFont->HasGlyph(*currChar)) &&
04168            !CCMAP_HAS_CHAR_EXT(gIgnorableCCMapExt, *currChar) &&
04169            !IS_RTL_PRESENTATION_FORM(*currChar))
04170       --currChar;
04171     fontSwitch.mFontWin = currFont;
04172     if (!(*aFunc)(&fontSwitch, currChar+1, firstChar - currChar, aData))
04173       return NS_OK;
04174     if (currChar == lastChar)
04175       return NS_OK;
04176     // continue with the next substring, re-using the available loaded fonts
04177     firstChar = currChar;
04178     if (IS_LOW_SURROGATE(*currChar) && (currChar-1) > lastChar && IS_HIGH_SURROGATE(*(currChar-1))) {
04179       currFont = LocateFont(aDC, SURROGATE_TO_UCS4(*(currChar-1), *currChar), count);
04180       currChar -= 2;
04181     }
04182     else {
04183       currFont = LocateFont(aDC, *currChar, count);
04184       --currChar;
04185     }
04186   }
04187 
04188   // see if we can keep the same font for adjacent characters
04189   PRInt32 lastCharLen;
04190   PRUint32 codepoint;
04191 
04192   while (currChar > lastChar) {
04193     if (IS_LOW_SURROGATE(*currChar) && (currChar-1) > lastChar && IS_HIGH_SURROGATE(*(currChar-1))) {
04194       codepoint =  SURROGATE_TO_UCS4(*(currChar-1), *currChar);
04195       nextFont = LocateFont(aDC, codepoint, count);
04196       lastCharLen = 2;
04197     }
04198     else {
04199       codepoint = *currChar;
04200       nextFont = LocateFont(aDC, codepoint, count);
04201       lastCharLen = 1;
04202     }
04203     if (nextFont != currFont ||
04204         /* render Hebrew and Arabic presentation forms and right-to-left
04205            characters outside the BMP one by one, because Windows doesn't reorder
04206            them. 
04207        XXX If a future version of Uniscribe corrects this, we will need to make a
04208            run-time check and set a rendering hint accordingly */
04209         codepoint > 0xFFFF ||
04210         IS_RTL_PRESENTATION_FORM(codepoint)) {
04211       // We have a substring that can be represented with the same font, and
04212       // we are about to switch fonts, it is time to notify our caller.
04213       fontSwitch.mFontWin = currFont;
04214       if (!(*aFunc)(&fontSwitch, currChar+1, firstChar - currChar, aData))
04215         return NS_OK;
04216       // continue with the next substring, re-using the available loaded fonts
04217       firstChar = currChar;
04218       currFont = nextFont; // use the font found earlier for the char
04219     }
04220     currChar -= lastCharLen;
04221   }
04222 
04223   //do it for last part of the string
04224   fontSwitch.mFontWin = currFont;
04225   (*aFunc)(&fontSwitch, currChar+1, firstChar - currChar, aData);
04226 
04227   return NS_OK;
04228 }
04229 
04230 //
04231 
04232 nsFontWin::nsFontWin(LOGFONT* aLogFont, HFONT aFont, PRUint16* aCCMap)
04233 {
04234   if (aLogFont) {
04235     strcpy(mName, aLogFont->lfFaceName);
04236   }
04237   mFont = aFont;
04238   mCCMap = aCCMap;
04239 }
04240 
04241 nsFontWin::~nsFontWin()
04242 {
04243   if (mFont) {
04244     ::DeleteObject(mFont);
04245     mFont = nsnull;
04246   }
04247 }
04248 
04249 PRInt32
04250 nsFontWin::GetWidth(HDC aDC, const char* aString, PRUint32 aLength)
04251 {
04252   SIZE size;
04253   ::GetTextExtentPoint32(aDC, aString, aLength, &size);
04254   size.cx -= mOverhangCorrection;
04255   return size.cx;
04256 }
04257 
04258 PRBool
04259 nsFontWin::FillClipRect(PRInt32 aX, PRInt32 aY, UINT aLength, UINT uOptions, RECT& clipRect)
04260 {
04261   if (!(uOptions & (ETO_CLIPPED | ETO_OPAQUE)) &&
04262       mOverhangCorrection > 0 && !(mPitchAndFamily & TMPF_FIXED_PITCH)) {
04263     // bug 52596 - although the clipping rectangle is said to be optional, we
04264     // have to use a clipping rectange to work around a GDI bug on
04265     // Win9X-Japanese that causes the text to be truncated incorrectly.
04266     clipRect.top = aY - mMaxHeightMetric;
04267     clipRect.bottom = aY + mMaxHeightMetric;
04268     clipRect.left = aX;
04269     clipRect.right = aX + mMaxCharWidthMetric * aLength;
04270     return PR_TRUE;
04271   }
04272   return PR_FALSE;
04273 }
04274 
04275 static PRBool
04276 NS_ExtTextOutA(HDC aDC, nsFontWin* aFont, PRInt32 aX, PRInt32 aY, UINT uOptions,
04277   LPCRECT lprc, LPCSTR aString, UINT aLength, INT *lpDx)
04278 {
04279   RECT clipRect;
04280   if (!lpDx && !lprc && aFont->FillClipRect(aX, aY, aLength, uOptions, clipRect)) {
04281     lprc = &clipRect;
04282     uOptions |= ETO_CLIPPED;
04283   }
04284   return ::ExtTextOutA(aDC, aX, aY, uOptions, lprc, aString, aLength, lpDx);
04285 }
04286 
04287 static PRBool
04288 NS_ExtTextOutW(HDC aDC, nsFontWin* aFont, PRInt32 aX, PRInt32 aY, UINT uOptions,
04289   LPCRECT lprc, LPCWSTR aString, UINT aLength, INT *lpDx)
04290 {
04291   RECT clipRect;
04292   if (!lpDx && !lprc && aFont->FillClipRect(aX, aY, aLength, uOptions, clipRect)) {
04293     lprc = &clipRect;
04294     uOptions |= ETO_CLIPPED;
04295   }
04296   return ::ExtTextOutW(aDC, aX, aY, uOptions, lprc, aString, aLength, lpDx);
04297 }
04298 
04299 void
04300 nsFontWin::DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
04301   const char* aString, PRUint32 aLength, INT* lpDx)
04302 {
04303   NS_ExtTextOutA(aDC, this, aX, aY, 0, NULL, aString, aLength, lpDx);
04304 }
04305 
04306 #ifdef MOZ_MATHML
04307 nsresult
04308 nsFontWin::GetBoundingMetrics(HDC                aDC, 
04309                               const char*        aString,
04310                               PRUint32           aLength,
04311                               nsBoundingMetrics& aBoundingMetrics)
04312 {
04313   return GetBoundingMetricsCommonA(aDC, mOverhangCorrection, aString, aLength, aBoundingMetrics);
04314 }
04315 #endif
04316 
04317 #ifdef DEBUG
04318 static void
04319 VerifyFontHasGlyph(nsFontWin* aFont, const PRUnichar* aString, PRInt32 aLength)
04320 {
04321   const PRUnichar* curr = aString;
04322   const PRUnichar* last = aString + aLength;
04323   PRUint32 ch;
04324   while (curr < last) {
04325     if (IS_HIGH_SURROGATE(*curr) && (curr+1) < last && 
04326         IS_LOW_SURROGATE(*(curr+1))) {
04327       ch = SURROGATE_TO_UCS4(*curr, *(curr+1));
04328       curr += 2;
04329     }
04330     else {
04331       ch = *curr;
04332       curr += 1;
04333     }
04334     NS_ASSERTION(aFont->HasGlyph(ch), "internal error");
04335   }
04336 }
04337 #define DEBUG_VERIFY_FONT_HASGLYPH(font, string, length) \
04338 VerifyFontHasGlyph(font, string, length)
04339 #else
04340 #define DEBUG_VERIFY_FONT_HASGLYPH(font, string, length)
04341 #endif
04342 
04343 nsFontWinUnicode::nsFontWinUnicode(LOGFONT* aLogFont, HFONT aFont,
04344   PRUint16* aCCMap) : nsFontWin(aLogFont, aFont, aCCMap)
04345 {
04346 // This is used for a bug in WIN95 where it does not render
04347 // unicode TrueType fonts with underline or strikeout correctly.
04348 // @see  nsFontWinUnicode::DrawString
04349   NS_ASSERTION(aLogFont != NULL, "Null logfont passed to nsFontWinUnicode constructor");
04350   mUnderlinedOrStrikeOut = aLogFont->lfUnderline || aLogFont->lfStrikeOut;
04351 }
04352 
04353 nsFontWinUnicode::~nsFontWinUnicode()
04354 {
04355 }
04356 
04357 PRInt32
04358 nsFontWinUnicode::GetWidth(HDC aDC, const PRUnichar* aString, PRUint32 aLength)
04359 {
04360   DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
04361   SIZE size;
04362   ::GetTextExtentPoint32W(aDC, aString, aLength, &size);
04363   size.cx -= mOverhangCorrection;
04364   return size.cx;
04365 }
04366 
04367 void
04368 nsFontWinUnicode::DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
04369   const PRUnichar* aString, PRUint32 aLength)
04370 {
04371   DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
04372   // Due to a bug in WIN95 unicode rendering of truetype fonts
04373   // with underline or strikeout, we need to set a clip rect
04374   // to prevent the underline and/or strikethru from being rendered
04375   // too far to the right of the character string.
04376   // The WIN95 bug causes the underline to be 20-30% longer than
04377   // it should be. @see bugzilla bug 8322
04378                            
04379   // Do check for underline or strikeout first since they are rarely
04380   // used. HTML text frames draw the underlines or strikeout rather
04381   // than relying on loading and underline or strikeout font so very
04382   // few fonts should have mUnderlinedOrStrikeOut set.
04383   if (mUnderlinedOrStrikeOut) {
04384     if (IsWin95OrWin98()) {
04385       // Clip out the extra underline/strikethru caused by the
04386       // bug in WIN95.
04387       SIZE size;
04388       ::GetTextExtentPoint32W(aDC, aString, aLength, &size);
04389       size.cx -= mOverhangCorrection;
04390       RECT clipRect;
04391       clipRect.top = aY - size.cy;
04392       clipRect.bottom = aY + size.cy; // Make it plenty large to allow for character descent.
04393                                       // Not necessary to clip vertically, only horizontally
04394       clipRect.left = aX;
04395       clipRect.right = aX + size.cx;
04396       NS_ExtTextOutW(aDC, this, aX, aY, ETO_CLIPPED, &clipRect, aString, aLength, NULL); 
04397       return;
04398     }
04399   } 
04400 
04401   // Do normal non-WIN95 text output without clipping
04402   NS_ExtTextOutW(aDC, this, aX, aY, 0, NULL, aString, aLength, NULL);  
04403 }
04404 
04405 #ifdef MOZ_MATHML
04406 nsresult
04407 nsFontWinUnicode::GetBoundingMetrics(HDC                aDC, 
04408                                      const PRUnichar*   aString,
04409                                      PRUint32           aLength,
04410                                      nsBoundingMetrics& aBoundingMetrics)
04411 {
04412   DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
04413   aBoundingMetrics.Clear();
04414   nsAutoChar16Buffer buffer;
04415 
04416   // at this stage, the glyph agent should have already been initialized
04417   // given that it was used to compute the x-height in RealizeFont()
04418   NS_ASSERTION(gGlyphAgent.GetState() != eGlyphAgent_UNKNOWN, "Glyph agent is not yet initialized");
04419   if (gGlyphAgent.GetState() != eGlyphAgent_UNICODE) {
04420     // we are on a platform that doesn't implement GetGlyphOutlineW() 
04421     // we need to use glyph indices
04422     nsresult rv = GetGlyphIndices(aDC, &mCMAP, aString, aLength, buffer);
04423     if (NS_FAILED(rv)) {
04424       return rv;
04425     }
04426   }
04427 
04428   return GetBoundingMetricsCommon(aDC, mOverhangCorrection, aString, aLength, aBoundingMetrics, buffer.get());
04429 }
04430 
04431 #ifdef NS_DEBUG
04432 void 
04433 nsFontWinUnicode::DumpFontInfo()
04434 {
04435   printf("FontName: %s @%p\n", mName, this);
04436   printf("FontType: nsFontWinUnicode\n");
04437 }
04438 #endif // NS_DEBUG
04439 #endif
04440 
04441 nsFontWinNonUnicode::nsFontWinNonUnicode(LOGFONT* aLogFont, HFONT aFont,
04442   PRUint16* aCCMap, nsIUnicodeEncoder* aConverter, PRBool aIsWide) : nsFontWin(aLogFont, aFont, aCCMap)
04443 {
04444   mConverter = aConverter;
04445   mIsWide = aIsWide;
04446 }
04447 
04448 nsFontWinNonUnicode::~nsFontWinNonUnicode()
04449 {
04450 }
04451 
04452 PRInt32
04453 nsFontWinNonUnicode::GetWidth(HDC aDC, const PRUnichar* aString,
04454   PRUint32 aLength)
04455 {
04456   DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
04457   nsAutoCharBuffer buffer;
04458 
04459   PRInt32 destLength = aLength;
04460   if (NS_FAILED(ConvertUnicodeToGlyph(aString, aLength, destLength, 
04461                 mConverter, mIsWide, buffer))) {
04462     return 0;
04463   }
04464 
04465   SIZE size;
04466   if (!mIsWide)
04467     ::GetTextExtentPoint32A(aDC, buffer.get(), destLength, &size);
04468   else
04469     ::GetTextExtentPoint32W(aDC, (const PRUnichar*) buffer.get(), destLength / 2, &size);
04470   size.cx -= mOverhangCorrection;
04471 
04472   return size.cx;
04473 }
04474 
04475 void
04476 nsFontWinNonUnicode::DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
04477   const PRUnichar* aString, PRUint32 aLength)
04478 {
04479   DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
04480   nsAutoCharBuffer buffer;
04481   PRInt32 destLength = aLength;
04482 
04483   if (NS_FAILED(ConvertUnicodeToGlyph(aString, aLength, destLength, 
04484                 mConverter, mIsWide, buffer))) {
04485     return;
04486   }
04487 
04488   if (!mIsWide)
04489     NS_ExtTextOutA(aDC, this, aX, aY, 0, NULL, buffer.get(), aLength, NULL);
04490   else 
04491     NS_ExtTextOutW(aDC, this, aX, aY, 0, NULL, (const PRUnichar*) buffer.get(), destLength / 2, NULL);
04492 }
04493 
04494 #ifdef MOZ_MATHML
04495 nsresult
04496 nsFontWinNonUnicode::GetBoundingMetrics(HDC                aDC, 
04497                                         const PRUnichar*   aString,
04498                                         PRUint32           aLength,
04499                                         nsBoundingMetrics& aBoundingMetrics)
04500 {
04501   DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
04502   aBoundingMetrics.Clear();
04503   nsAutoCharBuffer buffer;
04504   PRInt32 destLength = aLength;
04505   nsresult rv = NS_OK;
04506 
04507   rv = ConvertUnicodeToGlyph(aString, aLength, destLength, mConverter, 
04508                              mIsWide, buffer);
04509   if (NS_FAILED(rv))
04510     return rv;
04511 
04512   if (mIsWide) {
04513     nsAutoChar16Buffer buf;
04514     // at this stage, the glyph agent should have already been initialized
04515     // given that it was used to compute the x-height in RealizeFont()
04516     NS_ASSERTION(gGlyphAgent.GetState() != eGlyphAgent_UNKNOWN, "Glyph agent is not yet initialized");
04517     if (gGlyphAgent.GetState() != eGlyphAgent_UNICODE) {
04518       // we are on a platform that doesn't implement GetGlyphOutlineW() 
04519       // we need to use glyph indices
04520       rv = GetGlyphIndices(aDC, &mCMAP, (const PRUnichar*)buffer.get(), destLength / 2, buf);
04521       if (NS_FAILED(rv)) {
04522         return rv;
04523       }
04524     }
04525 
04526     // buffer.mBuffer is now a pseudo-Unicode string so that we can use 
04527     // GetBoundingMetricsCommon() also used by nsFontWinUnicode. 
04528     return  GetBoundingMetricsCommon(aDC, mOverhangCorrection, (const PRUnichar*)buffer.get(), 
04529               destLength / 2, aBoundingMetrics, buf.get());
04530 
04531   }
04532 
04533   return GetBoundingMetricsCommonA(aDC, mOverhangCorrection, buffer.get(), destLength, 
04534                                    aBoundingMetrics);
04535 }
04536 
04537 #ifdef NS_DEBUG
04538 void 
04539 nsFontWinNonUnicode::DumpFontInfo()
04540 {
04541   printf("FontName: %s @%p\n", mName, this);
04542   printf("FontType: nsFontWinNonUnicode\n");
04543 }
04544 #endif // NS_DEBUG
04545 #endif // MOZ_MATHML
04546 
04547 nsFontWinSubstitute::nsFontWinSubstitute(LOGFONT* aLogFont, HFONT aFont,
04548   PRUint16* aCCMap, PRBool aDisplayUnicode) : nsFontWin(aLogFont, aFont, aCCMap)
04549 {
04550   mDisplayUnicode = aDisplayUnicode;
04551   mIsForIgnorable = PR_FALSE; 
04552   memset(mRepresentableCharMap, 0, sizeof(mRepresentableCharMap));
04553 }
04554 
04555 nsFontWinSubstitute::nsFontWinSubstitute(PRUint16 *aCCMap) :
04556   nsFontWin(NULL, NULL, aCCMap)
04557 {
04558   mIsForIgnorable = PR_TRUE;
04559   mDisplayUnicode = PR_FALSE;
04560   memset(mRepresentableCharMap, 0, sizeof(mRepresentableCharMap));
04561 }
04562 
04563 nsFontWinSubstitute::~nsFontWinSubstitute()
04564 {
04565 }
04566 
04567 static nsresult
04568 SubstituteChars(PRBool              aDisplayUnicode,
04569                 const PRUnichar*    aString, 
04570                 PRUint32            aLength,
04571                 nsAutoChar16Buffer& aResult,
04572                 PRUint32*           aCount)
04573 {
04574 
04575 #ifdef WINCE
04576 // Unicode backend on WINCE... Substitute nothing.
04577 
04578   if (!aResult.EnsureElemCapacity(aLength))
04579     return NS_ERROR_OUT_OF_MEMORY;
04580 
04581   *aCount = aLength;
04582   memcpy(aResult.get(), aString, aLength * sizeof(PRUnichar));
04583   return NS_OK;
04584 
04585 #else
04586 
04587 
04588   nsresult res;
04589   if (!gFontSubstituteConverter) {
04590     CallCreateInstance(NS_SAVEASCHARSET_CONTRACTID, &gFontSubstituteConverter);
04591     if (gFontSubstituteConverter) {
04592       // if aDisplayUnicode is set: transliterate, and then fallback
04593       //   to literal Unicode points &#xNNNN; for unknown characters
04594       // otherwise: transliterate, and then fallback to entities for
04595       //   recorded characters and question marks for unknown characters
04596       res = gFontSubstituteConverter->Init("ISO-8859-1",
04597               aDisplayUnicode
04598               ? nsISaveAsCharset::attr_FallbackHexNCR
04599               : nsISaveAsCharset::attr_EntityAfterCharsetConv + nsISaveAsCharset::attr_FallbackQuestionMark + nsISaveAsCharset::attr_IgnoreIgnorables,
04600               nsIEntityConverter::transliterate);
04601       if (NS_FAILED(res)) {
04602         NS_RELEASE(gFontSubstituteConverter);
04603       }
04604     }
04605   }
04606 
04607   // do the transliteration if we have a converter
04608   PRUnichar* result; 
04609   if (gFontSubstituteConverter) {
04610     nsXPIDLCString conv;
04611     nsAutoString tmp(aString, aLength); // we need to pass a null-terminated string
04612     res = gFontSubstituteConverter->Convert(tmp.get(), getter_Copies(conv));
04613     if (NS_SUCCEEDED(res)) {
04614       *aCount = conv.Length();
04615       if (*aCount > 0) {
04616         if (!aResult.EnsureElemCapacity(*aCount)) {
04617           return NS_ERROR_OUT_OF_MEMORY;
04618         }
04619         result = aResult.get();
04620         PRUnichar* u = result;
04621         const char* c = conv.get();
04622         for (; *c; ++c, ++u) {
04623           *u = *c;
04624         }
04625       }
04626       return NS_OK;
04627     }
04628   }
04629 
04630   // we reach here if we couldn't transliterate, so fallback to question marks 
04631   if (!aResult.EnsureElemCapacity(aLength)) return NS_ERROR_OUT_OF_MEMORY;
04632   result = aResult.get();
04633   for (PRUint32 i = 0; i < aLength; i++) {
04634     result[i] = NS_REPLACEMENT_CHAR;
04635   }
04636   *aCount = aLength;
04637   return NS_OK;
04638 #endif // WINCE
04639 }
04640 
04641 PRInt32
04642 nsFontWinSubstitute::GetWidth(HDC aDC, const PRUnichar* aString,
04643   PRUint32 aLength)
04644 {
04645   if (mIsForIgnorable)
04646     return 0;
04647   nsAutoChar16Buffer buffer;
04648   nsresult rv = SubstituteChars(PR_FALSE, aString, aLength, buffer, &aLength);
04649   if (NS_FAILED(rv) || !aLength) return 0;
04650 
04651   SIZE size;
04652   ::GetTextExtentPoint32W(aDC, buffer.get(), aLength, &size);
04653   size.cx -= mOverhangCorrection;
04654 
04655   return size.cx;
04656 }
04657 
04658 void
04659 nsFontWinSubstitute::DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
04660   const PRUnichar* aString, PRUint32 aLength)
04661 {
04662   if (mIsForIgnorable)
04663     return;
04664   nsAutoChar16Buffer buffer;
04665   nsresult rv = SubstituteChars(PR_FALSE, aString, aLength, buffer, &aLength);
04666   if (NS_FAILED(rv) || !aLength) return;
04667 
04668   NS_ExtTextOutW(aDC, this, aX, aY, 0, NULL, buffer.get(), aLength, NULL);
04669 }
04670 
04671 #ifdef MOZ_MATHML
04672 nsresult
04673 nsFontWinSubstitute::GetBoundingMetrics(HDC                aDC, 
04674                                         const PRUnichar*   aString,
04675                                         PRUint32           aLength,
04676                                         nsBoundingMetrics& aBoundingMetrics)
04677 {
04678   aBoundingMetrics.Clear();
04679   if (mIsForIgnorable)
04680     return NS_OK;
04681   nsAutoChar16Buffer buffer;
04682   nsresult rv = SubstituteChars(mDisplayUnicode, aString, aLength, buffer, &aLength);
04683   if (NS_FAILED(rv)) {
04684     return rv;
04685   }
04686   if (!aLength) return NS_OK;
04687   nsAutoChar16Buffer buf;
04688 
04689   // at this stage, the glyph agent should have already been initialized
04690   // given that it was used to compute the x-height in RealizeFont()
04691   NS_ASSERTION(gGlyphAgent.GetState() != eGlyphAgent_UNKNOWN, "Glyph agent is not yet initialized");
04692   if (gGlyphAgent.GetState() != eGlyphAgent_UNICODE) {
04693     // we are on a platform that doesn't implement GetGlyphOutlineW() 
04694     // we better get all glyph indices in one swoop
04695     rv = GetGlyphIndices(aDC, &mCMAP, buffer.get(), aLength, buf);
04696     if (NS_FAILED(rv)) {
04697       return rv;
04698     }
04699   }
04700 
04701   return GetBoundingMetricsCommon(aDC, mOverhangCorrection, buffer.get(), aLength, 
04702                                   aBoundingMetrics, buf.get());
04703 }
04704 
04705 #ifdef NS_DEBUG
04706 void 
04707 nsFontWinSubstitute::DumpFontInfo()
04708 {
04709   printf("FontName: %s @%p\n", mIsForIgnorable ? "For the ignorable" : mName, this);
04710   printf("FontType: nsFontWinSubstitute\n");
04711 }
04712 #endif // NS_DEBUG
04713 #endif
04714 
04715 static PRUint16*
04716 GenerateDefault(nsCharsetInfo* aSelf)
04717 { 
04718   PRUint32 map[UCS2_MAP_LEN];
04719 
04720   memset(map, 0xff, sizeof(map));
04721   return MapToCCMap(map);
04722 }
04723 
04724 static PRUint16*
04725 GenerateSingleByte(nsCharsetInfo* aSelf)
04726 { 
04727   PRUint32 map[UCS2_MAP_LEN];
04728   PRUint8 mb[256];
04729   WCHAR wc[256];
04730   int i;
04731 
04732   memset(map, 0, sizeof(map));
04733   if (UseAFunctions()) {
04734     // A-functions use this function for TrueType
04735     for (i = 0; i <= 255; ++i) {
04736       mb[i] = i;
04737     }
04738   } else {
04739     memset(mb + 128, 0, 160 - 128);
04740     for (i = 0; i <= 127; ++i) {
04741       mb[i] = i;
04742     }
04743     mb[145] = 145;
04744     mb[146] = 146;
04745 
04746     if (aSelf->mCodePage == 1250) {
04747       mb[138] = 138;
04748       mb[140] = 140;
04749       mb[141] = 141;
04750       mb[142] = 142;
04751       mb[143] = 143;
04752       mb[154] = 154;
04753       mb[156] = 156;
04754       mb[158] = 158;
04755       mb[159] = 159;
04756     }
04757 
04758     for (i = 160; i <= 255; ++i) {
04759       mb[i] = i;
04760     }
04761 
04762     //win95/98 have problem in some raster fonts (MS Sans Serif and MS Serif) in
04763     //rendering 0xb7. So let's skip this in charmap, that will let system resort 
04764     //to other fonts.  
04765     if (IsWin95OrWin98())
04766       mb[0xb7] = 0;
04767   }
04768 
04769   int len = MultiByteToWideChar(aSelf->mCodePage, 0, (char*) mb, 256, wc, 256);
04770 #ifdef NS_DEBUG
04771   if (len != 256) {
04772     printf("%s: MultiByteToWideChar returned %d\n", aSelf->mName, len);
04773   }
04774 #endif
04775   for (i = 0; i <= 255; ++i) {
04776     ADD_GLYPH(map, wc[i]);
04777   }
04778   return MapToCCMap(map);
04779 }
04780 
04781 static PRUint16*
04782 GenerateMultiByte(nsCharsetInfo* aSelf)
04783 { 
04784   PRUint32 map[UCS2_MAP_LEN];
04785   memset(map, 0, sizeof(map));
04786   for (WCHAR c = 0; c < 0xFFFF; ++c) {
04787     BOOL defaulted = FALSE;
04788     WideCharToMultiByte(aSelf->mCodePage, 0, &c, 1, nsnull, 0, nsnull,
04789       &defaulted);
04790     if (!defaulted) {
04791       ADD_GLYPH(map, c);
04792     }
04793   }
04794   return MapToCCMap(map);
04795 }
04796 
04797 static int
04798 HaveConverterFor(PRUint8 aCharset)
04799 {
04800   WCHAR wc = 'a';
04801   char mb[8];
04802   if (WideCharToMultiByte(gCharsetInfo[gCharsetToIndex[aCharset]].mCodePage, 0,
04803                           &wc, 1, mb, sizeof(mb), nsnull, nsnull)) {
04804     return 1;
04805   }
04806   // remove from table, since we can't support it anyway
04807   for (int i = sizeof(gBitToCharset)-1; i >= 0; --i) {
04808     if (gBitToCharset[i] == aCharset) {
04809       gBitToCharset[i] = DEFAULT_CHARSET;
04810     }
04811   }
04812 
04813   return 0;
04814 }
04815 
04816 nsFontSubset::nsFontSubset()
04817   : nsFontWin(nsnull, nsnull, nsnull)
04818 {
04819 }
04820 
04821 nsFontSubset::~nsFontSubset()
04822 {
04823 }
04824 
04825 void
04826 nsFontSubset::Convert(const PRUnichar* aString, PRUint32 aLength,
04827   nsAutoCharBuffer& aResult, PRUint32* aResultLength)
04828 {
04829   *aResultLength = 0;
04830   // Get the number of bytes needed for the conversion
04831   int nb = WideCharToMultiByte(mCodePage, 0, aString, aLength,
04832                                nsnull, 0, nsnull, nsnull);
04833 
04834   if (!nb || !aResult.EnsureElemCapacity(nb)) return;
04835   char* buf = aResult.get();
04836   // Convert the Unicode string to ANSI
04837   *aResultLength = WideCharToMultiByte(mCodePage, 0, aString, aLength,
04838                                        buf, nb, nsnull, nsnull);
04839 }
04840 
04841 PRInt32
04842 nsFontSubset::GetWidth(HDC aDC, const PRUnichar* aString, PRUint32 aLength)
04843 {
04844   nsAutoCharBuffer buffer;
04845   Convert(aString, aLength, buffer, &aLength);
04846   if (aLength) {
04847     SIZE size;
04848     ::GetTextExtentPoint32A(aDC, buffer.get(), aLength, &size);
04849     size.cx -= mOverhangCorrection;
04850     return size.cx;
04851   }
04852   return 0;
04853 }
04854 
04855 void
04856 nsFontSubset::DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
04857   const PRUnichar* aString, PRUint32 aLength)
04858 {
04859   nsAutoCharBuffer buffer;
04860   Convert(aString, aLength, buffer, &aLength);
04861   if (aLength) {
04862     NS_ExtTextOutA(aDC, this, aX, aY, 0, NULL, buffer.get(), aLength, NULL);
04863   }
04864 }
04865 
04866 #ifdef MOZ_MATHML
04867 nsresult
04868 nsFontSubset::GetBoundingMetrics(HDC                aDC, 
04869                                  const PRUnichar*   aString,
04870                                  PRUint32           aLength,
04871                                  nsBoundingMetrics& aBoundingMetrics)
04872 {
04873   aBoundingMetrics.Clear();
04874   nsAutoCharBuffer buffer;
04875   Convert(aString, aLength, buffer, &aLength);
04876   if (aLength) {
04877     return GetBoundingMetricsCommonA(aDC, mOverhangCorrection, buffer.get(), aLength, 
04878                                      aBoundingMetrics);
04879   }
04880   return NS_OK;
04881 }
04882 
04883 #ifdef NS_DEBUG
04884 void 
04885 nsFontSubset::DumpFontInfo()
04886 {
04887   printf("FontName: %s @%p\n", mName, this);
04888   printf("FontType: nsFontSubset\n");
04889 }
04890 #endif // NS_DEBUG
04891 #endif
04892 
04893 nsFontSubsetSubstitute::nsFontSubsetSubstitute(PRBool aIsForIgnorable)
04894   : nsFontSubset(), mIsForIgnorable(aIsForIgnorable)
04895 {
04896 }
04897 
04898 nsFontSubsetSubstitute::~nsFontSubsetSubstitute()
04899 {
04900 }
04901 
04902 PRInt32
04903 nsFontSubsetSubstitute::GetWidth(HDC aDC, const PRUnichar* aString,
04904   PRUint32 aLength)
04905 {
04906   if (mIsForIgnorable)
04907     return 0;
04908 
04909   return nsFontSubset::GetWidth(aDC, aString, aLength);
04910 }
04911 
04912 void
04913 nsFontSubsetSubstitute::DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
04914   const PRUnichar* aString, PRUint32 aLength)
04915 {
04916   if (mIsForIgnorable)
04917     return;
04918 
04919   nsFontSubset::DrawString(aDC, aX, aY, aString, aLength);
04920 }
04921 
04922 #ifdef MOZ_MATHML
04923 nsresult
04924 nsFontSubsetSubstitute::GetBoundingMetrics(HDC                aDC, 
04925                                         const PRUnichar*   aString,
04926                                         PRUint32           aLength,
04927                                         nsBoundingMetrics& aBoundingMetrics)
04928 {
04929   aBoundingMetrics.Clear();
04930   if (mIsForIgnorable)
04931     return NS_OK;
04932 
04933   return nsFontSubset::GetBoundingMetrics(aDC, aString, aLength, 
04934                                           aBoundingMetrics);
04935 }
04936 
04937 #ifdef NS_DEBUG
04938 void 
04939 nsFontSubsetSubstitute::DumpFontInfo()
04940 {
04941   printf("FontName: %s @%p\n", mIsForIgnorable ? "For the ignorable" : mName, this);
04942   printf("FontType: nsFontSubsetSubstitute\n");
04943 }
04944 #endif // NS_DEBUG
04945 #endif
04946 
04947 void
04948 nsFontSubsetSubstitute::Convert(const PRUnichar* aString, PRUint32 aLength,
04949   nsAutoCharBuffer& aResult, PRUint32* aResultLength)
04950 {
04951   nsAutoChar16Buffer buffer;
04952   nsresult rv = SubstituteChars(PR_FALSE, aString, aLength, buffer, &aLength);
04953   if (NS_FAILED(rv)) {
04954     // this is the out-of-memory error case
04955     *aResultLength = 0;
04956     return;
04957   }
04958   if (!aLength) {
04959     // this is the case where the substitute string collapsed to nothingness
04960     *(aResult.get()) = '\0';
04961     *aResultLength = 0;
04962     return;
04963   }
04964   nsFontSubset::Convert(buffer.get(), aLength, aResult, aResultLength);
04965 }
04966 
04967 nsFontWinA::nsFontWinA(LOGFONT* aLogFont, HFONT aFont, PRUint16* aCCMap)
04968   : nsFontWin(aLogFont, aFont, aCCMap)
04969 {
04970   if (aLogFont) {
04971     mLogFont = *aLogFont;
04972   }
04973 }
04974 
04975 nsFontWinA::~nsFontWinA()
04976 {
04977   if (mSubsets) {
04978     nsFontSubset** subset = mSubsets;
04979     nsFontSubset** endSubsets = subset + mSubsetsCount;
04980     while (subset < endSubsets) {
04981       delete *subset;
04982       ++subset;
04983     }
04984     nsMemory::Free(mSubsets);
04985     mSubsets = nsnull;
04986   }
04987 }
04988 
04989 int
04990 nsFontWinA::GetSubsets(HDC aDC)
04991 {
04992   mSubsetsCount = 0;
04993 
04994   FONTSIGNATURE signature;
04995   if (::GetTextCharsetInfo(aDC, &signature, 0) == DEFAULT_CHARSET) {
04996     return 0;
04997   }
04998 
04999   int dword;
05000   DWORD* array = signature.fsCsb;
05001   int i = 0;
05002   for (dword = 0; dword < 2; ++dword) {
05003     for (int bit = 0; bit < sizeof(DWORD) * 8; ++bit, ++i) {
05004       if ((array[dword] >> bit) & 1) {
05005         PRUint8 charset = gBitToCharset[i];
05006 #ifdef DEBUG_FONT_SIGNATURE
05007         printf("  %02d %s\n", i, gCharsetInfo[gCharsetToIndex[charset]].mName);
05008 #endif
05009         if ((charset != DEFAULT_CHARSET) && HaveConverterFor(charset)) {
05010           ++mSubsetsCount;
05011         }
05012       }
05013     }
05014   }
05015 
05016   if (!mSubsetsCount) {
05017     return 0;
05018   }
05019   mSubsets = (nsFontSubset**) nsMemory::Alloc(mSubsetsCount* sizeof(nsFontSubset*));
05020   if (!mSubsets) {
05021     mSubsetsCount = 0;
05022     return 0;
05023   }
05024   memset(mSubsets, 0, mSubsetsCount * sizeof(nsFontSubset*)); 
05025 
05026   int j;
05027   for (j = 0; j < mSubsetsCount; ++j) {
05028     mSubsets[j] = new nsFontSubset();
05029     if (!mSubsets[j]) {
05030       for (j = j - 1; j >= 0; --j) {
05031         delete mSubsets[j];
05032       }
05033       nsMemory::Free(mSubsets);
05034       mSubsets = nsnull;
05035       mSubsetsCount = 0;
05036       return 0;
05037     }
05038   }
05039 
05040   i = j = 0;
05041   for (dword = 0; dword < 2; ++dword) {
05042     for (int bit = 0; bit < sizeof(DWORD) * 8; ++bit, ++i) {
05043       if ((array[dword] >> bit) & 1) {
05044         PRUint8 charset = gBitToCharset[i];
05045         if ((charset != DEFAULT_CHARSET) && HaveConverterFor(charset)) {
05046           mSubsets[j]->mCharset = charset;
05047           ++j;
05048         }
05049       }
05050     }
05051   }
05052 
05053   return 1;
05054 }
05055 
05056 PRInt32
05057 nsFontWinA::GetWidth(HDC aDC, const PRUnichar* aString, PRUint32 aLength)
05058 {
05059   NS_ERROR("must call nsFontSubset's GetWidth");
05060   return 0;
05061 }
05062 
05063 void
05064 nsFontWinA::DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
05065   const PRUnichar* aString, PRUint32 aLength)
05066 {
05067   NS_ERROR("must call nsFontSubset's DrawString");
05068 }
05069 
05070 nsFontSubset* 
05071 nsFontWinA::FindSubset(HDC aDC, PRUnichar aChar, nsFontMetricsWinA* aFontMetrics)
05072 {
05073   nsFontSubset **subsetPtr = mSubsets;
05074   nsFontSubset **endSubset = subsetPtr + mSubsetsCount;
05075 
05076   while (subsetPtr < endSubset) {
05077     if (!(*subsetPtr)->mCCMap)
05078       if (!(*subsetPtr)->Load(aDC, aFontMetrics, this))
05079         continue;
05080     if ((*subsetPtr)->HasGlyph(aChar)) {
05081       return *subsetPtr;
05082     }
05083     ++subsetPtr;
05084   }
05085   return nsnull;
05086 }
05087 
05088 
05089 #ifdef MOZ_MATHML
05090 nsresult
05091 nsFontWinA::GetBoundingMetrics(HDC                aDC, 
05092                                const PRUnichar*   aString,
05093                                PRUint32           aLength,
05094                                nsBoundingMetrics& aBoundingMetrics)
05095 {
05096   NS_ERROR("must call nsFontSubset's GetBoundingMetrics");
05097   return NS_ERROR_FAILURE;
05098 }
05099 
05100 #ifdef NS_DEBUG
05101 void 
05102 nsFontWinA::DumpFontInfo()
05103 {
05104   NS_ERROR("must call nsFontSubset's DumpFontInfo");
05105 }
05106 #endif // NS_DEBUG
05107 #endif
05108 
05109 nsFontWin*
05110 nsFontMetricsWinA::LoadFont(HDC aDC, const nsString& aName, PRBool aNameQuirks)
05111 {
05112   LOGFONT logFont;
05113   HFONT hfont = CreateFontHandle(aDC, aName, &logFont);
05114   if (hfont) {
05115 #ifdef DEBUG_FONT_SIGNATURE
05116     printf("%s\n", logFont.lfFaceName);
05117 #endif
05118     HFONT oldFont = (HFONT)::SelectObject(aDC, (HGDIOBJ)hfont);
05119     char name[sizeof(logFont.lfFaceName)];
05120     if (::GetTextFace(aDC, sizeof(name), name) &&
05121         !strcmpi(name, logFont.lfFaceName)) {
05122       PRUint16* ccmap = GetCCMAP(aDC, logFont.lfFaceName, 
05123         nsnull, nsnull, nsnull);
05124       if (ccmap) {
05125         nsFontWinA* font = new nsFontWinA(&logFont, hfont, ccmap);
05126         if (font) {
05127           if (font->GetSubsets(aDC)) {
05128             // XXX InitMetricsFor(aDC, font) is not here, except if
05129             // we can assume that it is the same for all subsets?
05130             mLoadedFonts.AppendElement(font);
05131             ::SelectObject(aDC, (HGDIOBJ)oldFont);
05132             return font;
05133           }
05134           ::SelectObject(aDC, (HGDIOBJ)oldFont);
05135           delete font; // will release hfont as well
05136           return nsnull;
05137         }
05138         // do not free 'map', it is cached in the gFontMaps hashtable and
05139         // it is going to be deleted by the cleanup observer
05140       }
05141     }
05142     ::SelectObject(aDC, (HGDIOBJ)oldFont);
05143     ::DeleteObject(hfont);
05144   }
05145   return nsnull;
05146 }
05147 
05148 nsFontWin*
05149 nsFontMetricsWinA::LoadGlobalFont(HDC aDC, nsGlobalFont* aGlobalFont)
05150 {
05151   LOGFONT logFont;
05152   HFONT hfont = CreateFontHandle(aDC, aGlobalFont, &logFont);
05153   if (hfont) {
05154     nsFontWinA* font = new nsFontWinA(&logFont, hfont, aGlobalFont->ccmap);
05155     if (font) {
05156       HFONT oldFont = (HFONT)::SelectObject(aDC, (HGDIOBJ)hfont);
05157       if (font->GetSubsets(aDC)) {
05158         // XXX InitMetricsFor(aDC, font) is not here, except if
05159         // we can assume that it is the same for all subsets?
05160         mLoadedFonts.AppendElement(font);
05161         ::SelectObject(aDC, (HGDIOBJ)oldFont);
05162         return font;
05163       }
05164       ::SelectObject(aDC, (HGDIOBJ)oldFont);
05165       delete font; // will release hfont as well
05166       return nsnull;
05167     }
05168     ::DeleteObject(hfont);
05169   }
05170   return nsnull;
05171 }
05172 
05173 int
05174 nsFontSubset::Load(HDC aDC, nsFontMetricsWinA* aFontMetricsWinA, nsFontWinA* aFont)
05175 {
05176   LOGFONT* logFont = &aFont->mLogFont;
05177   logFont->lfCharSet = mCharset;
05178   // create a font handle without filling & overwriting what is in logFont
05179   HFONT hfont = (aFontMetricsWinA->Font().sizeAdjust <= 0) 
05180     ? ::CreateFontIndirect(logFont)
05181     : aFontMetricsWinA->CreateFontAdjustHandle(aDC, logFont);
05182   if (hfont) {
05183     int i = gCharsetToIndex[mCharset];
05184     if (!gCharsetInfo[i].mCCMap)
05185       gCharsetInfo[i].mCCMap = gCharsetInfo[i].GenerateMap(&gCharsetInfo[i]);
05186     if (!gCharsetInfo[i].mCCMap) {
05187       ::DeleteObject(hfont);
05188       return 0;
05189     }
05190     mCCMap = gCharsetInfo[i].mCCMap;
05191     mCodePage = gCharsetInfo[i].mCodePage;
05192     mFont = hfont;
05193 
05194     //XXX can we safely assume the same metrics for all subsets and remove this?
05195     HFONT oldFont = (HFONT)::SelectObject(aDC, (HGDIOBJ)hfont);
05196     aFontMetricsWinA->InitMetricsFor(aDC, this);
05197     ::SelectObject(aDC, (HGDIOBJ)oldFont);
05198 
05199     return 1;
05200   }
05201   return 0;
05202 }
05203 
05204 nsFontWin*
05205 nsFontMetricsWinA::GetFontFor(HFONT aHFONT)
05206 {
05207   int count = mLoadedFonts.Count();
05208   for (int i = 0; i < count; ++i) {
05209     nsFontWinA* font = (nsFontWinA*)mLoadedFonts[i];
05210     nsFontSubset** subset = font->mSubsets;
05211     nsFontSubset** endSubsets = subset + font->mSubsetsCount;
05212     while (subset < endSubsets) {
05213       if ((*subset)->mFont == aHFONT) {
05214         return *subset;
05215       }
05216       ++subset;
05217     }
05218   }
05219   NS_ERROR("Cannot find the font that owns the handle");
05220   return nsnull;
05221 }
05222 
05223 nsFontWin*
05224 nsFontMetricsWinA::FindLocalFont(HDC aDC, PRUint32 aChar)
05225 {
05226   while (mFontsIndex < mFonts.Count()) {
05227     if (mFontsIndex == mGenericIndex) {
05228       return nsnull;
05229     }
05230     nsString* name = mFonts.StringAt(mFontsIndex++);
05231     nsAutoString winName; 
05232     PRBool found = LookupWinFontName(*name, winName); 
05233     nsFontWinA* font = (nsFontWinA*)LoadFont(aDC, found ? winName : *name);
05234     if (font && font->HasGlyph(aChar)) {
05235       nsFontSubset* subset = font->FindSubset(aDC, (PRUnichar)aChar, this);
05236       if (subset) 
05237         return subset;
05238     }
05239   }
05240   return nsnull;
05241 }
05242 
05243 nsFontWin*
05244 nsFontMetricsWinA::LoadGenericFont(HDC aDC, PRUint32 aChar, const nsString& aName)
05245 {
05246   for (int i = mLoadedFonts.Count()-1; i >= 0; --i) {
05247 
05248     if (aName.EqualsIgnoreCase(((nsFontWin*)mLoadedFonts[i])->mName))
05249       return nsnull;
05250 
05251   }
05252   nsFontWinA* font = (nsFontWinA*)LoadFont(aDC, aName);
05253   if (font && font->HasGlyph(aChar)) {
05254     return font->FindSubset(aDC, (PRUnichar)aChar, this);
05255   }
05256   return nsnull;
05257 }
05258 
05259 static int
05260 SystemSupportsChar(PRUnichar aChar)
05261 {
05262   for (int i = 0; i < sizeof(gBitToCharset); ++i) {
05263     PRUint8 charset = gBitToCharset[i];
05264     if (charset == DEFAULT_CHARSET) 
05265       continue;
05266     if (!HaveConverterFor(charset)) 
05267       continue;
05268     int j = gCharsetToIndex[charset];
05269     if (!gCharsetInfo[j].mCCMap) {
05270       gCharsetInfo[j].mCCMap = gCharsetInfo[j].GenerateMap(&gCharsetInfo[j]);
05271       if (!gCharsetInfo[j].mCCMap) 
05272           return 0;
05273     }
05274     if (CCMAP_HAS_CHAR(gCharsetInfo[j].mCCMap, aChar)) 
05275       return 1;
05276   }
05277 
05278   return 0;
05279 }
05280 
05281 nsFontWin*
05282 nsFontMetricsWinA::FindGlobalFont(HDC aDC, PRUint32 c)
05283 {
05284   if (!gGlobalFonts) {
05285     if (!InitializeGlobalFonts(aDC)) {
05286       return nsnull;
05287     }
05288   }
05289   if (!SystemSupportsChar(c)) {
05290     return nsnull;
05291   }
05292   int count = gGlobalFonts->Count();
05293   for (int i = 0; i < count; ++i) {
05294     nsGlobalFont* globalFont = (nsGlobalFont*)gGlobalFonts->ElementAt(i); 
05295     if (globalFont->flags & NS_GLOBALFONT_SKIP) {
05296       continue;
05297     }
05298     if (!globalFont->ccmap) {
05299       // don't adjust here, we just want to quickly get the CMAP. Adjusting
05300       // is meant to only happen when loading the final font in LoadFont()
05301       HFONT hfont = ::CreateFontIndirect(&globalFont->logFont);
05302       if (!hfont) {
05303         continue;
05304       }
05305       HFONT oldFont = (HFONT)::SelectObject(aDC, hfont);
05306       globalFont->ccmap = GetCCMAP(aDC, globalFont->logFont.lfFaceName,
05307         nsnull, nsnull, nsnull);
05308       ::SelectObject(aDC, oldFont);
05309       ::DeleteObject(hfont);
05310       if (!globalFont->ccmap || globalFont->ccmap == gEmptyCCMap) {
05311         globalFont->flags |= NS_GLOBALFONT_SKIP;
05312         continue;
05313       }
05314       if (SameAsPreviousMap(i)) {
05315         continue;
05316       }
05317     }
05318     if (CCMAP_HAS_CHAR(globalFont->ccmap, c)) {
05319       nsFontWinA* font = (nsFontWinA*)LoadGlobalFont(aDC, globalFont);
05320       if (!font) {
05321         // disable this global font because when LoadGlobalFont() fails,
05322         // this means that no subset of interest was found in the font
05323         globalFont->flags |= NS_GLOBALFONT_SKIP;
05324         continue;
05325       }
05326       nsFontSubset* subset = font->FindSubset(aDC, (PRUnichar)c, this);
05327       if (subset) {
05328         return subset;
05329       }
05330       mLoadedFonts.RemoveElement(font);
05331       delete font;
05332     }
05333   }
05334 
05335   return nsnull;
05336 }
05337 
05338 nsFontWinSubstituteA::nsFontWinSubstituteA(LOGFONT* aLogFont, HFONT aFont,
05339   PRUint16* aCCMap) : nsFontWinA(aLogFont, aFont, aCCMap),
05340   mIsForIgnorable(PR_FALSE)
05341 {
05342   memset(mRepresentableCharMap, 0, sizeof(mRepresentableCharMap));
05343 }
05344 
05345 nsFontWinSubstituteA::nsFontWinSubstituteA(PRUint16* aCCMap) :
05346   nsFontWinA(NULL, NULL, aCCMap),
05347   mIsForIgnorable(PR_TRUE)
05348 {
05349   memset(mRepresentableCharMap, 0, sizeof(mRepresentableCharMap));
05350 }
05351 
05352 nsFontWinSubstituteA::~nsFontWinSubstituteA()
05353 {
05354 }
05355 
05356 nsFontWin*
05357 nsFontMetricsWinA::FindSubstituteFont(HDC aDC, PRUint32 aChar)
05358 {
05359   // @see nsFontMetricsWin::FindSubstituteFont() for the general idea behind
05360   // this function. The fundamental difference here in nsFontMetricsWinA is
05361   // that the substitute font is setup as a 'wrapper' around a 'substitute
05362   // subset' that has a glyph for the replacement character. This allows
05363   // a transparent integration with all the other 'A' functions. 
05364 
05365   if (mSubstituteFont) {
05366     //make the char representable so that we don't have to go over all font before fallback to 
05367     //subsituteFont.
05368     ((nsFontWinSubstituteA*)mSubstituteFont)->SetRepresentable(aChar);
05369     return ((nsFontWinA*)mSubstituteFont)->mSubsets[0];
05370   }
05371 
05372   // Try local/loaded fonts first
05373   int i, count = mLoadedFonts.Count();
05374   for (i = 0; i < count; ++i) {
05375     nsFontWinA* font = (nsFontWinA*)mLoadedFonts[i];
05376     if (font->HasGlyph(NS_REPLACEMENT_CHAR)) {
05377       nsFontSubset* subset = font->FindSubset(aDC, NS_REPLACEMENT_CHAR, this);
05378       if (subset) {
05379         // make a substitute font from this one
05380         nsAutoString name;
05381         name.AssignWithConversion(font->mName);
05382         nsFontWinSubstituteA* substituteFont = (nsFontWinSubstituteA*)LoadSubstituteFont(aDC, name);
05383         if (substituteFont) {
05384           nsFontSubset* substituteSubset = substituteFont->mSubsets[0];
05385           substituteSubset->mCharset = subset->mCharset;
05386           if (substituteSubset->Load(aDC, this, substituteFont)) {
05387             substituteFont->SetRepresentable(aChar);
05388             mSubstituteFont = (nsFontWin*)substituteFont;
05389             return substituteSubset;
05390           }
05391           mLoadedFonts.RemoveElement(substituteFont);
05392           delete substituteFont;
05393         }
05394       }
05395     }
05396   }
05397 
05398   // Try global fonts
05399   // Since we reach here after FindGlobalFont() is called, we have already
05400   // scanned the global list of fonts and have set the attributes of interest
05401   count = gGlobalFonts->Count();
05402   for (i = 0; i < count; ++i) {
05403     nsGlobalFont* globalFont = (nsGlobalFont*)gGlobalFonts->ElementAt(i);
05404     if (!globalFont->ccmap || 
05405         globalFont->flags & NS_GLOBALFONT_SKIP) {
05406       continue;
05407     }
05408     if (CCMAP_HAS_CHAR(globalFont->ccmap, NS_REPLACEMENT_CHAR)) {
05409       // to find out the subset of interest, we will load this font for a moment
05410       BYTE charset = DEFAULT_CHARSET;
05411       nsFontWinA* font = (nsFontWinA*)LoadGlobalFont(aDC, globalFont);
05412       if (!font) {
05413         globalFont->flags |= NS_GLOBALFONT_SKIP;
05414         continue;
05415       }
05416       nsFontSubset* subset = font->FindSubset(aDC, NS_REPLACEMENT_CHAR, this);
05417       if (subset) {
05418         charset = subset->mCharset;
05419       }
05420       mLoadedFonts.RemoveElement(font);
05421       delete font;
05422       if (charset != DEFAULT_CHARSET) {
05423         // make a substitute font now
05424         nsFontWinSubstituteA* substituteFont = (nsFontWinSubstituteA*)LoadSubstituteFont(aDC, globalFont->name);
05425         if (substituteFont) {
05426           nsFontSubset* substituteSubset = substituteFont->mSubsets[0];
05427           substituteSubset->mCharset = charset;
05428           if (substituteSubset->Load(aDC, this, substituteFont)) {
05429             substituteFont->SetRepresentable(aChar);
05430             mSubstituteFont = (nsFontWin*)substituteFont;
05431             return substituteSubset;
05432           }
05433           mLoadedFonts.RemoveElement(substituteFont);
05434           delete substituteFont;
05435         }
05436       }
05437     }
05438   }
05439 
05440   // if we ever reach here, the replacement char should be changed to a more common char
05441   NS_ERROR("Could not provide a substititute font");
05442   return nsnull;
05443 }
05444 
05445 nsFontWin*
05446 nsFontMetricsWinA::LoadSubstituteFont(HDC aDC, const nsString& aName)
05447 {
05448   LOGFONT logFont;
05449   HFONT hfont = CreateFontHandle(aDC, aName, &logFont);
05450   if (hfont) {
05451     HFONT oldFont = (HFONT)::SelectObject(aDC, (HGDIOBJ)hfont);
05452     char name[sizeof(logFont.lfFaceName)];
05453     if (::GetTextFace(aDC, sizeof(name), name) &&
05454         !strcmpi(name, logFont.lfFaceName)) {
05455       nsFontWinSubstituteA* font = new nsFontWinSubstituteA(&logFont, hfont, nsnull);
05456       if (font) {
05457         font->mSubsets = (nsFontSubset**)nsMemory::Alloc(sizeof(nsFontSubset*));
05458         if (font->mSubsets) {
05459           font->mSubsets[0] = nsnull;
05460           nsFontSubsetSubstitute* subset = new nsFontSubsetSubstitute();
05461           if (subset) {
05462             font->mSubsetsCount = 1;
05463             font->mSubsets[0] = subset;
05464             mLoadedFonts.AppendElement((nsFontWin*)font);
05465             ::SelectObject(aDC, (HGDIOBJ)oldFont);
05466             return font;
05467           }
05468         }
05469         ::SelectObject(aDC, (HGDIOBJ)oldFont);
05470         delete font; // will release hfont, and mSubsets if there, as well
05471         return nsnull;
05472       }
05473     }
05474     ::SelectObject(aDC, (HGDIOBJ)oldFont);
05475     ::DeleteObject(hfont);
05476   }
05477   return nsnull;
05478 }
05479 
05480 nsFontSubset*
05481 nsFontMetricsWinA::LocateFontSubset(HDC aDC, PRUnichar aChar, PRInt32 & aCount, nsFontWinA*& aFont)
05482 {
05483   nsFontSubset *fontSubset;
05484   PRInt32 i;
05485 
05486   // see if one of our loaded fonts can represent the character
05487   for (i = 0; i < aCount; ++i) {
05488     aFont = (nsFontWinA*)mLoadedFonts[i];
05489     if (aFont->HasGlyph(aChar)) {
05490       fontSubset = aFont->FindSubset(aDC, aChar, this);
05491       if (fontSubset)
05492         return fontSubset;
05493     }
05494   }
05495 
05496   fontSubset = (nsFontSubset*)FindFont(aDC, aChar);
05497   aFont = nsnull;   //this simply means we don't know and don't bother to figure out
05498   aCount = mLoadedFonts.Count(); // update since FindFont() can change it
05499   return fontSubset;
05500 }
05501 
05502 nsresult
05503 nsFontMetricsWinA::ResolveForwards(HDC                  aDC,
05504                                    const PRUnichar*     aString,
05505                                    PRUint32             aLength,
05506                                    nsFontSwitchCallback aFunc, 
05507                                    void*                aData)
05508 {
05509   NS_ASSERTION(aString || !aLength, "invalid call");
05510   const PRUnichar* firstChar = aString;
05511   const PRUnichar* lastChar  = aString + aLength;
05512   const PRUnichar* currChar  = firstChar;
05513   nsFontSubset* currSubset;
05514   nsFontSubset* nextSubset;
05515   nsFontWinA* currFont;
05516   PRInt32 count;
05517   nsFontSwitch fontSwitch;
05518 
05519   if (firstChar == lastChar)
05520     return NS_OK;
05521 
05522   // see if one of our loaded fonts can represent the current character
05523   count = mLoadedFonts.Count();
05524   currSubset = LocateFontSubset(aDC, *currChar, count, currFont);
05525 
05526   //This if block is meant to speedup the process in normal situation, when
05527   //most characters can be found in first font
05528   NS_ASSERTION(count > 1, "only one font loaded");
05529   // mLoadedFont[0] == font for invisible ignorable characters
05530   PRUint32 firstFont = count > 1 ? 1 : 0; 
05531   if (currFont == mLoadedFonts[firstFont]) { 
05532     while (++currChar < lastChar && 
05533            currFont->HasGlyph(*currChar) && currSubset->HasGlyph(*currChar) &&
05534            !CCMAP_HAS_CHAR_EXT(gIgnorableCCMapExt, *currChar))
05535       ;
05536 
05537     fontSwitch.mFontWin = currSubset;
05538     if (!(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData))
05539       return NS_OK;
05540     if (currChar == lastChar)
05541       return NS_OK;
05542     // continue with the next substring, re-using the available loaded fonts
05543     firstChar = currChar;
05544     currSubset = LocateFontSubset(aDC, *currChar, count, currFont); 
05545   }
05546 
05547   while (++currChar < lastChar) {
05548     nextSubset = LocateFontSubset(aDC, *currChar, count, currFont);
05549     if (nextSubset != currSubset) {
05550       // We have a substring that can be represented with the same font, and
05551       // we are about to switch fonts, it is time to notify our caller.
05552       fontSwitch.mFontWin = currSubset;
05553       if (!(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData))
05554         return NS_OK;
05555       // continue with the next substring, re-using the available loaded fonts
05556       firstChar = currChar;
05557       currSubset = nextSubset; // use the font found earlier for the char
05558     }
05559   }
05560 
05561   //do it for last part of the string
05562   fontSwitch.mFontWin = currSubset;
05563   NS_ASSERTION(currSubset, "invalid font here. ");
05564   (*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData);
05565 
05566   return NS_OK;
05567 }
05568 
05569 nsresult
05570 nsFontMetricsWinA::ResolveBackwards(HDC                  aDC,
05571                                     const PRUnichar*     aString,
05572                                     PRUint32             aLength,
05573                                     nsFontSwitchCallback aFunc, 
05574                                     void*                aData)
05575 {
05576   NS_ASSERTION(aString || !aLength, "invalid call");
05577   const PRUnichar* firstChar = aString + aLength - 1;
05578   const PRUnichar* lastChar  = aString - 1;
05579   const PRUnichar* currChar  = firstChar;
05580   nsFontSubset* currSubset;
05581   nsFontSubset* nextSubset;
05582   nsFontWinA* currFont;
05583   PRInt32 count;
05584   nsFontSwitch fontSwitch;
05585 
05586   if (firstChar == lastChar)
05587     return NS_OK;
05588 
05589   // see if one of our loaded fonts can represent the current character
05590   count = mLoadedFonts.Count();
05591   currSubset = LocateFontSubset(aDC, *currChar, count, currFont);
05592 
05593   while (--currChar < lastChar) {
05594     nextSubset = LocateFontSubset(aDC, *currChar, count, currFont);
05595     if (nextSubset != currSubset) {
05596       // We have a substring that can be represented with the same font, and
05597       // we are about to switch fonts, it is time to notify our caller.
05598       fontSwitch.mFontWin = currSubset;
05599       if (!(*aFunc)(&fontSwitch, firstChar, firstChar - currChar, aData))
05600         return NS_OK;
05601       // continue with the next substring, re-using the available loaded fonts
05602       firstChar = currChar;
05603       currSubset = nextSubset; // use the font found earlier for the char
05604     }
05605   }
05606 
05607   //do it for last part of the string
05608   fontSwitch.mFontWin = currSubset;
05609   (*aFunc)(&fontSwitch, firstChar, firstChar - currChar, aData);
05610 
05611   return NS_OK;
05612 }
05613 
05614 // The Font Enumerator
05615 
05616 nsFontEnumeratorWin::nsFontEnumeratorWin()
05617 {
05618 }
05619 
05620 NS_IMPL_ISUPPORTS1(nsFontEnumeratorWin,nsIFontEnumerator)
05621 
05622 static int gInitializedFontEnumerator = 0;
05623 
05624 static int
05625 InitializeFontEnumerator(void)
05626 {
05627   gInitializedFontEnumerator = 1;
05628   if (!nsFontMetricsWin::gGlobalFonts) {
05629     HDC dc = ::GetDC(nsnull);
05630     if (!nsFontMetricsWin::InitializeGlobalFonts(dc)) {
05631       ::ReleaseDC(nsnull, dc);
05632       return 0;
05633     }
05634     ::ReleaseDC(nsnull, dc);
05635   }
05636 
05637   return 1;
05638 }
05639 
05640 static int
05641 CompareFontNames(const void* aArg1, const void* aArg2, void* aClosure)
05642 {
05643   const PRUnichar* str1 = *((const PRUnichar**) aArg1);
05644   const PRUnichar* str2 = *((const PRUnichar**) aArg2);
05645 
05646   // XXX add nsICollation stuff
05647 
05648   return nsCRT::strcmp(str1, str2);
05649 }
05650 
05651 static int
05652 SignatureMatchesLangGroup(FONTSIGNATURE* aSignature,
05653   const char* aLangGroup)
05654 {
05655   int dword;
05656 
05657   // hack : FONTSIGNATURE in Win32 doesn't have a separate signature field
05658   // for zh-HK.  We have to treat it as zh-TW.
05659   const char *langGroup = strcmp(aLangGroup, "zh-HK") ? aLangGroup : "zh-TW";
05660 
05661   // For scripts that have been supported by 'ANSI' codepage in Win9x/ME,
05662   // we can rely on fsCsb. 
05663   DWORD* array = aSignature->fsCsb;
05664   int i = 0;
05665   for (dword = 0; dword < 2; ++dword) {
05666     for (int bit = 0; bit < sizeof(DWORD) * 8; ++bit) {
05667       if ((array[dword] >> bit) & 1) {
05668         if (!strcmp(gCharsetInfo[gCharsetToIndex[gBitToCharset[i]]].mLangGroup,
05669                     langGroup)) {
05670           return 1;
05671         }
05672       }
05673       ++i;
05674     }
05675   }
05676 
05677   // For aLangGroup corresponding to one of 'ANSI' codepages, the negative
05678   // result from fsCsb should be considered final. Otherwise, we risk getting
05679   // a false positive from fsUsb, which could lead unncessarily to 
05680   // a mix of glyphs from different fonts.
05681 
05682   // x-western .. zh-TW. (exclude JOHAB)
05683   for (i = eCharset_ANSI; i <= eCharset_CHINESEBIG5; ++i) 
05684   {
05685     if (!strcmp(gCharsetInfo[i].mLangGroup, langGroup))
05686       return 0;
05687   }
05688 
05689   // For other scripts, we need fsUsb (Unicode coverage bitfield : 128bit).
05690   // Here we're just examining the first 3 dwords because at the moment
05691   // only the first 84 bits are assigned according to the MSDN.
05692 
05693   array = aSignature->fsUsb;
05694   for (i = 0, dword = 0; dword < 3; ++dword) {
05695     for (int bit = 0; bit < sizeof(DWORD) * 8; ++bit) {
05696       if ((array[dword] >> bit) & 1) {
05697         PRUint8 range = gBitToUnicodeRange[i];
05698         if (kRangeSpecificItemNum > range &&
05699             !strcmp(gUnicodeRangeToLangGroupTable[range], langGroup)) {
05700           return 1;
05701         }
05702       }
05703       ++i;
05704     }
05705   }
05706 
05707   return 0;
05708 }
05709 
05710 static int
05711 FontMatchesGenericType(nsGlobalFont* aFont, const char* aGeneric)
05712 {
05713   PRUint8 family = aFont->logFont.lfPitchAndFamily & 0xF0;
05714   PRUint8 pitch = aFont->logFont.lfPitchAndFamily & 0x0F;
05715 
05716   // Japanese 'Mincho' fonts do not belong to FF_MODERN even if
05717   // they are fixed pitch because they have variable stroke width.
05718   if (family == FF_ROMAN && pitch & FIXED_PITCH) {
05719     return !strcmp(aGeneric, "monospace");
05720   }
05721 
05722   // Japanese 'Gothic' fonts do not belong to FF_SWISS even if
05723   // they are variable pitch because they have constant stroke width.
05724   if (family == FF_MODERN && pitch & VARIABLE_PITCH) {
05725     return !strcmp(aGeneric, "sans-serif");
05726   }
05727 
05728   // All other fonts will be grouped correctly using family...
05729   switch (family) {
05730     case FF_DONTCARE:   return 1;
05731     case FF_ROMAN:      return !strcmp(aGeneric, "serif");
05732     case FF_SWISS:      return !strcmp(aGeneric, "sans-serif");
05733     case FF_MODERN:     return !strcmp(aGeneric, "monospace");
05734     case FF_SCRIPT:     return !strcmp(aGeneric, "cursive");
05735     case FF_DECORATIVE: return !strcmp(aGeneric, "fantasy");
05736   }
05737 
05738   return 0;
05739 }
05740 
05741 static nsresult
05742 EnumerateMatchingFonts(const char* aLangGroup,
05743   const char* aGeneric, PRUint32* aCount, PRUnichar*** aResult)
05744 {
05745   // aLangGroup=null or ""  means any (i.e., don't care)
05746   // aGeneric=null or ""  means any (i.e, don't care)
05747 
05748   NS_ENSURE_ARG_POINTER(aCount);
05749   NS_ENSURE_ARG_POINTER(aResult);
05750 
05751   *aCount = 0;
05752   *aResult = nsnull;
05753 
05754   if (aLangGroup && *aLangGroup && 
05755      (!strcmp(aLangGroup, "x-unicode") ||
05756       !strcmp(aLangGroup, "x-user-def"))) {
05757     return EnumerateMatchingFonts(nsnull, nsnull, aCount, aResult);
05758   }
05759 
05760   if (!gInitializedFontEnumerator) {
05761     if (!InitializeFontEnumerator()) {
05762       return NS_ERROR_FAILURE;
05763     }
05764   }
05765 
05766   int count = nsFontMetricsWin::gGlobalFonts->Count();
05767   PRUnichar** array = (PRUnichar**)nsMemory::Alloc(count * sizeof(PRUnichar*));
05768   if (!array) {
05769     return NS_ERROR_OUT_OF_MEMORY;
05770   }
05771   int j = 0;
05772   for (int i = 0; i < count; ++i) {
05773     nsGlobalFont* font = (nsGlobalFont*)nsFontMetricsWin::gGlobalFonts->ElementAt(i);
05774     PRBool accept = PR_TRUE;
05775     if (aLangGroup && *aLangGroup) {
05776       accept = SignatureMatchesLangGroup(&font->signature, aLangGroup);
05777     }
05778     if (accept && aGeneric && *aGeneric) {
05779       accept = FontMatchesGenericType(font, aGeneric);
05780     }
05781     if (accept) {
05782       PRUnichar* str = ToNewUnicode(font->name);
05783       if (!str) {
05784         for (j = j - 1; j >= 0; --j) {
05785           nsMemory::Free(array[j]);
05786         }
05787         nsMemory::Free(array);
05788         return NS_ERROR_OUT_OF_MEMORY;
05789       }
05790       array[j] = str;
05791       ++j;
05792     }
05793   }
05794 
05795   NS_QuickSort(array, j, sizeof(PRUnichar*), CompareFontNames, nsnull);
05796 
05797   *aCount = j;
05798   *aResult = array;
05799 
05800   return NS_OK;
05801 }
05802 
05803 NS_IMETHODIMP
05804 nsFontEnumeratorWin::EnumerateAllFonts(PRUint32* aCount, PRUnichar*** aResult)
05805 {
05806   return EnumerateMatchingFonts(nsnull, nsnull, aCount, aResult);
05807 }
05808 
05809 NS_IMETHODIMP
05810 nsFontEnumeratorWin::EnumerateFonts(const char* aLangGroup,
05811   const char* aGeneric, PRUint32* aCount, PRUnichar*** aResult)
05812 {
05813   return EnumerateMatchingFonts(aLangGroup, aGeneric, aCount, aResult);
05814 }
05815 
05816 NS_IMETHODIMP
05817 nsFontEnumeratorWin::HaveFontFor(const char* aLangGroup, PRBool* aResult)
05818 {
05819   NS_ENSURE_ARG_POINTER(aLangGroup);
05820   NS_ENSURE_ARG_POINTER(aResult);
05821 
05822   *aResult = PR_FALSE;
05823   if ((!strcmp(aLangGroup, "x-unicode")) ||
05824       (!strcmp(aLangGroup, "x-user-def"))) {
05825     *aResult = PR_TRUE;
05826     return NS_OK;
05827   }
05828   if (!gInitializedFontEnumerator) {
05829     if (!InitializeFontEnumerator()) {
05830       return NS_ERROR_FAILURE;
05831     }
05832   }
05833   int count = nsFontMetricsWin::gGlobalFonts->Count();
05834   for (int i = 0; i < count; ++i) {
05835     nsGlobalFont* font = (nsGlobalFont*)nsFontMetricsWin::gGlobalFonts->ElementAt(i);
05836     if (SignatureMatchesLangGroup(&font->signature, aLangGroup)) {
05837        *aResult = PR_TRUE;
05838        return NS_OK;
05839     }
05840   }
05841   return NS_OK;
05842 }
05843 
05844 NS_IMETHODIMP
05845 nsFontEnumeratorWin::GetDefaultFont(const char *aLangGroup, 
05846   const char *aGeneric, PRUnichar **aResult)
05847 {
05848   // aLangGroup=null or ""  means any (i.e., don't care)
05849   // aGeneric=null or ""  means any (i.e, don't care)
05850 
05851   NS_ENSURE_ARG_POINTER(aResult);
05852   *aResult = nsnull;
05853 
05854   return NS_OK;
05855 }
05856 
05857 NS_IMETHODIMP
05858 nsFontEnumeratorWin::UpdateFontList(PRBool *updateFontList)
05859 {
05860   PRBool haveFontForLang = PR_FALSE;
05861   int charsetCounter = 0;
05862   PRUint16 maskBitBefore = 0;
05863 
05864   // initialize updateFontList
05865   *updateFontList = PR_FALSE;
05866 
05867   // iterate langGoup; skip DEFAULT
05868   for (charsetCounter = 1; charsetCounter < eCharset_COUNT; ++charsetCounter) {
05869     HaveFontFor(gCharsetInfo[charsetCounter].mLangGroup, &haveFontForLang);
05870     if (haveFontForLang) {
05871       maskBitBefore |= PR_BIT(charsetCounter);
05872       haveFontForLang = PR_FALSE;
05873     }
05874   }
05875 
05876   // delete gGlobalFonts
05877   if (nsFontMetricsWin::gGlobalFonts) {
05878     for (int i = nsFontMetricsWin::gGlobalFonts->Count()-1; i >= 0; --i) {
05879       nsGlobalFont* font = (nsGlobalFont*)nsFontMetricsWin::gGlobalFonts->ElementAt(i);
05880       delete font;
05881     }
05882     delete nsFontMetricsWin::gGlobalFonts;
05883     nsFontMetricsWin::gGlobalFonts = nsnull;
05884   }
05885 
05886   // reconstruct gGlobalFonts
05887   HDC dc = ::GetDC(nsnull);
05888   if (!nsFontMetricsWin::InitializeGlobalFonts(dc)) {
05889     ::ReleaseDC(nsnull, dc);
05890     return NS_ERROR_FAILURE;
05891   }
05892   ::ReleaseDC(nsnull, dc);
05893 
05894   PRUint16 maskBitAfter = 0;
05895   // iterate langGoup again; skip DEFAULT
05896   for (charsetCounter = 1; charsetCounter < eCharset_COUNT; ++charsetCounter) {
05897     HaveFontFor(gCharsetInfo[charsetCounter].mLangGroup, &haveFontForLang);
05898     if (haveFontForLang) {
05899       maskBitAfter |= PR_BIT(charsetCounter);
05900       haveFontForLang = PR_FALSE;
05901     }
05902   }
05903 
05904   // check for change
05905   *updateFontList = (maskBitBefore != maskBitAfter);
05906   return NS_OK;
05907 }
05908 
05909 // See bug 231426 and references therein for the motivation and need to
05910 // do this. Especially, see http://www.trigeminal.com/samples/font_choices.html
05911 
05912 /* static */ 
05913 PRBool LookupWinFontName(const nsAFlatString& aName, nsAString& aWinName)
05914 {
05915   // to speed up start-up, bypass the property look-up for these fonts
05916   if (aName.LowerCaseEqualsLiteral("tahoma") ||
05917       aName.LowerCaseEqualsLiteral("arial") ||
05918       aName.LowerCaseEqualsLiteral("times new roman") ||
05919       aName.LowerCaseEqualsLiteral("courier new"))
05920     return PR_FALSE;
05921 
05922   if (!gFontNameMapProperties)
05923     NS_LoadPersistentPropertiesFromURISpec(&gFontNameMapProperties,
05924       NS_LITERAL_CSTRING("resource://gre/res/fonts/fontNameMap.properties"));
05925 
05926   if (!gFontNameMapProperties) {
05927     NS_WARNING("fontNameMap.properties is not available"); 
05928     return PR_FALSE;
05929   }
05930 
05931   nsAutoString name(aName); 
05932   ToLowerCase(name); 
05933 
05934   NS_ConvertUTF16toUTF8 propKey(name);
05935   propKey.StripWhitespace(); 
05936 
05937   if (IsASCII(propKey)) {
05938     // see if there's the native name in the current codepage
05939     // <ascii name>.cp<codepage>=<native name>
05940     LossyAppendUTF16toASCII(*gCodepageStr, propKey); 
05941     return NS_SUCCEEDED(gFontNameMapProperties->
05942                         GetStringProperty(propKey, aWinName));
05943   }
05944 
05945   // <native name>=<ascii name>.cp<codepage>
05946   if (NS_SUCCEEDED(gFontNameMapProperties->
05947                    GetStringProperty(propKey, aWinName))) {
05948     if (StringEndsWith(aWinName, *gCodepageStr)) {
05949       // if font codepage == current codepage, use the native name
05950       return PR_FALSE;
05951     }
05952     // if font codepage != current codepage, map to the ASCII name by
05953     // truncating '.cpXXX' (6 characters) at the end. 
05954     // aWinName ends with '.cpXXX' where 'XXX' is 932,936,949 or 950.
05955     aWinName.Truncate(aWinName.Length() - 6);
05956     return PR_TRUE;
05957   }
05958   return PR_FALSE;  // native name not listed in the properties file.
05959 }