Back to index

lightning-sunbird  0.9+nobinonly
nsMacUnicodeFontInfo.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Frank Yung-Fong Tang <ftang@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038  
00039 #include "nsMacUnicodeFontInfo.h"
00040 #include "nsCRT.h"
00041 #include "prmem.h"
00042 #include <Fonts.h>
00043 
00044 //#define DEBUG_TRUE_TYPE
00045 #include "nsICharRepresentable.h"
00046 #include "nsCompressedCharMap.h"
00047 #include "nsIObserver.h"
00048 #include "nsIObserverService.h"
00049 #include "nsIServiceManager.h"
00050 #include "nsDependentString.h"
00051 #include "nsLiteralString.h"
00052 #include "nsDeviceContextMac.h"
00053 #include "nsICharsetConverterManager.h"
00054 #include "nsIPersistentProperties2.h"
00055 #include "nsNetUtil.h"
00056 #include "nsHashtable.h"
00057 #include <ATSTypes.h>
00058 #include <SFNTTypes.h>
00059 #include <SFNTLayoutTypes.h>
00060 
00061 //#define TRACK_INIT_PERFORMANCE
00062 
00063 #ifdef TRACK_INIT_PERFORMANCE
00064 #include <DriverServices.h>
00065 #endif
00066 
00067 class nsFontCleanupObserver : public nsIObserver {
00068 public:
00069   NS_DECL_ISUPPORTS
00070   NS_DECL_NSIOBSERVER
00071 
00072   nsFontCleanupObserver() { }
00073   virtual ~nsFontCleanupObserver() {}
00074 };
00075 
00076 NS_IMPL_ISUPPORTS1(nsFontCleanupObserver, nsIObserver)
00077 
00078 NS_IMETHODIMP nsFontCleanupObserver::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
00079 {
00080   if (! nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID,aTopic))
00081   {
00082     nsMacUnicodeFontInfo::FreeGlobals();
00083   }
00084   return NS_OK;
00085 }
00086 
00087 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
00088 
00089 static nsIPersistentProperties* gFontEncodingProperties = nsnull;
00090 static nsICharsetConverterManager* gCharsetManager = nsnull;
00091 static nsObjectHashtable* gFontMaps = nsnull;
00092 static nsFontCleanupObserver *gFontCleanupObserver = nsnull;
00093 static PRUint16* gCCMap = nsnull;
00094 
00095 
00096 #ifdef IS_BIG_ENDIAN 
00097 # undef GET_SHORT
00098 # define GET_SHORT(p) (*((PRUint16*)p))
00099 # undef GET_LONG
00100 # define GET_LONG(p)  (*((PRUint32*)p))
00101 #else
00102 # ifdef IS_LITTLE_ENDIAN 
00103 #  undef GET_SHORT
00104 #  define GET_SHORT(p) (((p)[0] << 8) | (p)[1])
00105 #  undef GET_LONG
00106 #  define GET_LONG(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3])
00107 # endif
00108 #endif
00109 
00110 // The following should be defined in ATSTypes.h, but they ar not
00111 enum {
00112   kFMOpenTypeFontTechnology     = FOUR_CHAR_CODE('OTTO')
00113 };
00114 
00115 // The following should be defined in SNFTTypes.h, but they ar not
00116 enum {
00117   headFontTableTag = FOUR_CHAR_CODE('head'),
00118   locaFontTableTag = FOUR_CHAR_CODE('loca')
00119 };
00120 
00121 #define ADD_GLYPH(a,b) SET_REPRESENTABLE(a,b)
00122 #define FONT_HAS_GLYPH(a,b) IS_REPRESENTABLE(a,b)
00123 
00124 #undef SET_SPACE
00125 #define SET_SPACE(c) ADD_GLYPH(spaces, c)
00126 #undef SHOULD_BE_SPACE
00127 #define SHOULD_BE_SPACE(c) FONT_HAS_GLYPH(spaces, c)
00128 
00129 static PRInt8
00130 GetIndexToLocFormat(FMFont aFont)
00131 {
00132   PRUint16 indexToLocFormat;
00133   ByteCount len = 0;
00134   OSStatus err = ::FMGetFontTable(aFont, headFontTableTag, 50, 2, &indexToLocFormat, nsnull);
00135   if (err != noErr) 
00136     return -1;
00137     
00138   if (!indexToLocFormat) 
00139     return 0;
00140     
00141   return 1;
00142 }
00143 
00144 static PRUint8*
00145 GetSpaces(FMFont aFont, PRUint32* aMaxGlyph)
00146 {
00147   PRInt8 isLong = GetIndexToLocFormat(aFont);
00148   if (isLong < 0) 
00149     return nsnull;
00150 
00151   ByteCount len = 0;
00152   OSStatus err = ::FMGetFontTable(aFont, locaFontTableTag, 0, 0,  NULL, &len);
00153   
00154   if ((err != noErr) || (!len))
00155     return nsnull;
00156   
00157   PRUint8* buf = (PRUint8*) nsMemory::Alloc(len);
00158   NS_ASSERTION(buf, "cannot read 'loca' table because out of memory");
00159   if (!buf) 
00160     return nsnull;
00161   
00162   ByteCount newLen = 0;
00163   err = ::FMGetFontTable(aFont, locaFontTableTag, 0, len, buf, &newLen);
00164   NS_ASSERTION((newLen == len), "cannot read 'loca' table from the font");
00165   
00166   if (newLen != len) 
00167   {
00168     nsMemory::Free(buf);
00169     return nsnull;
00170   }
00171 
00172   if (isLong) 
00173   {
00174     PRUint32 longLen = ((len / 4) - 1);
00175     *aMaxGlyph = longLen;
00176     PRUint32* longBuf = (PRUint32*) buf;
00177     for (PRUint32 i = 0; i < longLen; i++) 
00178     {
00179       if (longBuf[i] == longBuf[i+1]) 
00180         buf[i] = 1;
00181       else 
00182         buf[i] = 0;
00183     }
00184   }
00185   else 
00186   {
00187     PRUint32 shortLen = ((len / 2) - 1);
00188     *aMaxGlyph = shortLen;
00189     PRUint16* shortBuf = (PRUint16*) buf;
00190     for (PRUint16 i = 0; i < shortLen; i++) 
00191     {
00192       if (shortBuf[i] == shortBuf[i+1]) 
00193         buf[i] = 1;
00194       else 
00195         buf[i] = 0;
00196     }
00197   }
00198 
00199   return buf;
00200 }
00201 
00202 static int spacesInitialized = 0;
00203 static PRUint32 spaces[2048];
00204 static void InitSpace()
00205 {
00206   if (!spacesInitialized) 
00207   {
00208     spacesInitialized = 1;
00209     SET_SPACE(0x0020);
00210     SET_SPACE(0x00A0);
00211     for (PRUint16 c = 0x2000; c <= 0x200B; c++) 
00212       SET_SPACE(c);
00213     SET_SPACE(0x3000);
00214   }
00215 }
00216 
00217 static void HandleFormat4(PRUint16* aEntry, PRUint8* aEnd, 
00218                             PRUint8* aIsSpace,  PRUint32 aMaxGlyph,
00219                             PRUint32* aFontInfo)
00220 {
00221   // notice aIsSpace could be nsnull in case of OpenType font
00222   PRUint8* end = aEnd;  
00223   PRUint16* s = aEntry;
00224   PRUint16 segCount = CFSwapInt16BigToHost(s[3]) / 2;
00225   PRUint16* endCode = &s[7];
00226   PRUint16* startCode = endCode + segCount + 1;
00227   PRUint16* idDelta = startCode + segCount;
00228   PRUint16* idRangeOffset = idDelta + segCount;
00229   PRUint16* glyphIdArray = idRangeOffset + segCount;
00230 
00231   PRUint16 i;
00232   InitSpace();
00233   
00234   for (i = 0; i < segCount; i++) 
00235   {
00236     if (idRangeOffset[i]) 
00237     {
00238       PRUint16 startC = CFSwapInt16BigToHost(startCode[i]);
00239       PRUint16 endC = CFSwapInt16BigToHost(endCode[i]);
00240       for (PRUint32 c = startC; c <= endC; c++) 
00241       {
00242         PRUint16* g = (CFSwapInt16BigToHost(idRangeOffset[i])/2 + (c - startC) + &idRangeOffset[i]);
00243         if ((PRUint8*) g < end) 
00244         {
00245           if (*g) 
00246           {
00247             PRUint16 glyph = CFSwapInt16BigToHost(idDelta[i]) + *g;
00248             if (glyph < aMaxGlyph) 
00249             {
00250               if (aIsSpace && aIsSpace[glyph]) 
00251               {
00252                 if (SHOULD_BE_SPACE(c)) 
00253                   ADD_GLYPH(aFontInfo, c);
00254               }
00255               else 
00256               {
00257                 ADD_GLYPH(aFontInfo, c);
00258               }
00259             }
00260           }
00261         }
00262         else 
00263         {
00264           // XXX should we trust this font at all if it does this?
00265         }
00266       }
00267     }
00268     else 
00269     {
00270       PRUint16 endC = CFSwapInt16BigToHost(endCode[i]);
00271       for (PRUint32 c = CFSwapInt16BigToHost(startCode[i]); c <= endC; c++) 
00272       {
00273         PRUint16 glyph = CFSwapInt16BigToHost(idDelta[i]) + c;
00274         if (glyph < aMaxGlyph) 
00275         {
00276           if (aIsSpace && aIsSpace[glyph]) 
00277           {
00278             if (SHOULD_BE_SPACE(c)) 
00279               ADD_GLYPH(aFontInfo, c);
00280           }
00281           else 
00282           {
00283             ADD_GLYPH(aFontInfo, c);
00284           }
00285         }
00286       }
00287     }
00288   }
00289 }
00290 static PRBool FillFontInfoFromCMAP(FMFont aFont, PRUint32 *aFontInfo, FourCharCode aFontFormat)
00291 {
00292   ByteCount len;
00293   OSErr err = ::FMGetFontTable(aFont, cmapFontTableTag, 0, 0, NULL, &len);
00294   if((err!=noErr) || (!len))
00295     return PR_FALSE;
00296 
00297   PRUint8* buf = (PRUint8*) nsMemory::Alloc(len);
00298   NS_ASSERTION(buf, "cannot read cmap because out of memory");
00299   if (!buf) 
00300     return PR_FALSE;
00301 
00302   ByteCount newLen;
00303   err = ::FMGetFontTable(aFont, cmapFontTableTag, 0, len,  buf, &newLen);
00304   NS_ASSERTION(newLen == len, "cannot read cmap from the font");
00305   if (newLen != len) 
00306   {
00307     nsMemory::Free(buf);
00308     return PR_FALSE;
00309   }
00310   
00311   PRUint8* p = buf + sizeof(PRUint16); // skip version, move to numberSubtables
00312   PRUint16 n = GET_SHORT(p); // get numberSubtables
00313   p += sizeof(PRUint16); // skip numberSubtables, move to the encoding subtables
00314 
00315   PRUint16 i;
00316   PRUint32 offset;
00317   PRUint32 platformUnicodeOffset = 0;
00318   // we look for platform =3 and encoding =1, 
00319   // if we cannot find it but there are a platform = 0 there, we 
00320   // remmeber that one and use it.
00321   
00322   for (i = 0; i < n; i++) 
00323   {
00324     PRUint16 platformID = GET_SHORT(p); // get platformID
00325     p += sizeof(PRUint16); // move to platformSpecificID
00326     PRUint16 encodingID = GET_SHORT(p); // get platformSpecificID
00327     p += sizeof(PRUint16); // move to offset
00328     offset = GET_LONG(p);  // get offset
00329     p += sizeof(PRUint32); // move to next entry
00330 #ifdef DEBUG_TRUE_TYPE
00331     printf("p=%d e=%d offset=%x\n", platformID, encodingID, offset);
00332 #endif
00333     if (platformID == kFontMicrosoftPlatform) 
00334     { 
00335       if (encodingID == kFontMicrosoftStandardScript) 
00336       { // Unicode
00337         // Some fonts claim to be unicode when they are actually
00338         // 'pseudo-unicode' fonts that require a converter...
00339         break;  // break out from for(;;) loop
00340       } //if (encodingID == kFontMicrosoftStandardScript)
00341 #if 0
00342       // if we have other encoding, we can still handle it, so... don't return this early
00343       else if (encodingID == kFontMicrosoftSymbolScript) 
00344       { // symbol      
00345         NS_ASSERTION(false, "cannot handle symbol font");
00346         nsMemory::Free(buf);
00347         return PR_FALSE;
00348       } 
00349 #endif
00350     } // if (platformID == kFontMicrosoftPlatform)  
00351     else {
00352       if (platformID == kFontUnicodePlatform) 
00353       { // Unicode
00354         platformUnicodeOffset = offset;
00355       }
00356     }
00357   } // for loop
00358   
00359   NS_ASSERTION((i != n) || ( 0 != platformUnicodeOffset), "do not know the TrueType encoding");
00360   if ((i == n) && ( 0 == platformUnicodeOffset)) 
00361   {  
00362     nsMemory::Free(buf);
00363     return PR_FALSE;
00364   }
00365 
00366   // usually, we come here for the entry platform = 3 encoding = 1
00367   // or if we don't have it but we have a platform = 0 (platformUnicodeOffset != 0)
00368   if(platformUnicodeOffset)
00369     offset = platformUnicodeOffset;
00370 
00371   p = buf + offset;
00372   PRUint16 format = GET_SHORT(p);
00373   NS_ASSERTION((kSFNTLookupSegmentArray == format), "hit some unknow format");
00374   switch(format) {
00375     case kSFNTLookupSegmentArray: // format 4
00376     {
00377       PRUint32 maxGlyph;
00378       PRUint8* isSpace = GetSpaces(aFont, &maxGlyph);
00379       // isSpace could be nsnull if the font do not have 'loca' table on Mac.
00380       // Two reason for that:
00381       // First, 'loca' table is not required in OpenType font.
00382       // 
00383       // Second, on Mac, the sfnt-housed font may not have 'loca' table. 
00384       // exmaple are Beijing and Taipei font.
00385       // see the WARNING section at the following link for details
00386       // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
00387 
00388       HandleFormat4((PRUint16*) (buf + offset), buf+len, isSpace, maxGlyph, aFontInfo);
00389 
00390       if (isSpace)
00391         nsMemory::Free(isSpace);
00392       nsMemory::Free(buf);                                
00393       return PR_TRUE;
00394     }
00395     break;
00396     default:
00397     {
00398       nsMemory::Free(buf);
00399       return PR_FALSE;
00400     }
00401     break;    
00402   }
00403   
00404 }
00405 
00406 
00407 
00408 static PRUint16* InitGlobalCCMap()
00409 {
00410   PRUint32 info[2048];
00411   memset(info, 0, sizeof(info));
00412 
00413 #ifdef TRACK_INIT_PERFORMANCE
00414   AbsoluteTime startTime;
00415   AbsoluteTime endTime;
00416   startTime = UpTime();
00417 #endif  
00418   
00419   FMFontFamilyIterator aFontIterator;
00420   OSStatus status = 0;
00421   FMFont aFont; 
00422   FMFontFamily aFontFamily;
00423   status = ::FMCreateFontFamilyIterator(NULL, NULL, kFMDefaultOptions,
00424                                         &aFontIterator);
00425   while (status == noErr)
00426   {
00427     FourCharCode aFormat;
00428     status = ::FMGetNextFontFamily(&aFontIterator, &aFontFamily);
00429     OSStatus status2;
00430     FMFontStyle aStyle;
00431     status2 = ::FMGetFontFromFontFamilyInstance(aFontFamily, 0, &aFont, &aStyle);
00432     NS_ASSERTION(status2 == noErr, "cannot get font from family");
00433     if (status2 == noErr)
00434     {
00435       status2 = ::FMGetFontFormat(aFont, &aFormat);
00436 #ifdef DEBUG_TRUE_TYPE
00437       OSStatus status3 = ::FMGetFontFormat(aFont, &aFormat);
00438       const char *four = (const char*) &aFormat;
00439       Str255 familyName;
00440       status3 = ::FMGetFontFamilyName(aFontFamily, familyName);
00441       familyName[familyName[0]+1] = '\0';
00442       printf("%s format = %c%c%c%c\n", familyName+1, *four, *(four+1), *(four+2), *(four+3));
00443 #endif
00444      if ((status2 == noErr) && 
00445          ((kFMTrueTypeFontTechnology == aFormat) ||
00446           (kFMOpenTypeFontTechnology == aFormat)))
00447      {
00448        PRBool ret = FillFontInfoFromCMAP(aFont, info, aFormat);
00449      }
00450     }
00451   }
00452   // Dispose of the contents of the font iterator.
00453   status = ::FMDisposeFontFamilyIterator(&aFontIterator);  
00454   
00455   PRUint16* map = MapToCCMap(info);
00456   NS_ASSERTION(map, "cannot create the compressed map");
00457 
00458   //register an observer to take care of cleanup
00459   gFontCleanupObserver = new nsFontCleanupObserver();
00460   NS_ASSERTION(gFontCleanupObserver, "failed to create observer");
00461   if (gFontCleanupObserver) {
00462     // register for shutdown
00463     nsresult rv;
00464     nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1", &rv));
00465     if (NS_SUCCEEDED(rv)) {
00466       rv = observerService->AddObserver(gFontCleanupObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
00467     }    
00468   }
00469     
00470 #ifdef TRACK_INIT_PERFORMANCE
00471   endTime = UpTime();
00472   Nanoseconds diff = ::AbsoluteToNanoseconds(SubAbsoluteFromAbsolute(endTime, startTime));
00473   printf("nsMacUnicodeFontInfo::InitGolbal take %d %d nanosecond\n", diff.hi, diff.lo);
00474 #endif
00475 
00476   return map;
00477 }
00478 
00479 // Helper to determine if a font has a private encoding that we know something about
00480 static nsresult
00481 GetEncoding(const nsCString& aFontName, nsACString& aValue)
00482 {
00483   nsresult rv;
00484   // see if we should init the property
00485   if (! gFontEncodingProperties) {
00486     // but bail out for common fonts used at startup...
00487     if (aFontName.EqualsLiteral("Lucida Grande") ||
00488         aFontName.EqualsLiteral("Charcoal") ||
00489         aFontName.EqualsLiteral("Chicago") ||
00490         aFontName.EqualsLiteral("Capitals") ||
00491         aFontName.EqualsLiteral("Gadget") ||
00492         aFontName.EqualsLiteral("Sand") ||
00493         aFontName.EqualsLiteral("Techno") ||
00494         aFontName.EqualsLiteral("Textile") ||
00495         aFontName.EqualsLiteral("Geneva") )
00496       return NS_ERROR_NOT_AVAILABLE; // error mean do not get a special encoding
00497 
00498     // init the property now
00499     rv = NS_LoadPersistentPropertiesFromURISpec(&gFontEncodingProperties,
00500          NS_LITERAL_CSTRING("resource://gre/res/fonts/fontEncoding.properties"));
00501     if NS_FAILED(rv)
00502       return rv;
00503   }
00504 
00505   nsCAutoString name(NS_LITERAL_CSTRING("encoding.") +
00506                      aFontName +
00507                      NS_LITERAL_CSTRING(".ttf"));
00508   name.StripWhitespace();
00509   ToLowerCase(name);
00510 
00511   nsAutoString value;
00512   rv = gFontEncodingProperties->GetStringProperty(name, value);
00513   if (NS_SUCCEEDED(rv))
00514     CopyUCS2toASCII(value, aValue);
00515   return rv;
00516 }
00517 
00518 // This function uses the charset converter manager (CCM) to get a pointer on 
00519 // the converter for the font whose name is given. The CCM caches the converter.
00520 // The caller holds a reference and should take care of the release.
00521 static nsresult
00522 GetConverter(const nsCString& aFontName, nsIUnicodeEncoder** aConverter)
00523 {
00524   *aConverter = nsnull;
00525 
00526   nsCAutoString value;
00527   nsresult rv = GetEncoding(aFontName, value);
00528   if (NS_FAILED(rv)) return rv;
00529   
00530   if (!gCharsetManager)
00531   {
00532     rv = CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
00533     if(NS_FAILED(rv)) return rv;
00534   }
00535   
00536   rv = gCharsetManager->GetUnicodeEncoderRaw(value.get(), aConverter);
00537   if (NS_FAILED(rv)) return rv;
00538 
00539   nsIUnicodeEncoder* tmp = *aConverter;
00540   return tmp->SetOutputErrorBehavior(tmp->kOnError_Replace, nsnull, '?');
00541 }
00542 
00543 // This function uses the charset converter manager to fill the map for the
00544 // font whose name is given
00545 static PRUint16*
00546 GetCCMapThroughConverter(nsIUnicodeEncoder *converter)
00547 {
00548   // see if we know something about the converter of this font 
00549   nsCOMPtr<nsICharRepresentable> mapper(do_QueryInterface(converter));
00550   return (mapper ? MapperToCCMap(mapper) : nsnull);
00551 }
00552 
00553 static PRBool PR_CALLBACK
00554 HashtableFreeCCMap(nsHashKey *aKey, void *aData, void *closure)
00555 {
00556     PRUint16* ccmap = (PRUint16*)aData;
00557     FreeCCMap(ccmap);
00558     return PR_TRUE;
00559 }
00560 
00561 // If the font is symbolic, get its converter and its compressed character map
00562 // (CCMap). The caller holds a reference to the converter (@see GetConverter()).
00563 // The CCMap is cached in a hashtable and will be freed at shutdown.
00564 nsresult
00565 nsMacUnicodeFontInfo::GetConverterAndCCMap(const nsString& aFontName, nsIUnicodeEncoder** aConverter,
00566     PRUint16** aCCMap)
00567 {
00568     if(NS_SUCCEEDED(GetConverter(NS_ConvertUCS2toUTF8(aFontName), aConverter)) && *aConverter)
00569     {
00570         // make sure we have the hashtable
00571         if(!gFontMaps)
00572         {
00573             gFontMaps = new nsObjectHashtable(nsnull, nsnull, HashtableFreeCCMap, nsnull);
00574             if(!gFontMaps)
00575             {
00576                 *aConverter = nsnull;
00577                 return NS_ERROR_OUT_OF_MEMORY;
00578             }
00579         }
00580 
00581         // first try to retrieve the ccmap for this font from the hashtable
00582         nsStringKey hashKey(aFontName);
00583         *aCCMap = (PRUint16*) gFontMaps->Get(&hashKey);
00584         if(!*aCCMap)
00585         {
00586             // if it's not already in the hashtable, create it and add it to the hashtable
00587             *aCCMap = GetCCMapThroughConverter(*aConverter);
00588             if(!*aCCMap)
00589             {
00590                 *aConverter = nsnull;
00591                 return NS_ERROR_FAILURE;
00592             }
00593             gFontMaps->Put(&hashKey, *aCCMap);
00594         }
00595         return NS_OK;
00596     }
00597     return NS_ERROR_FAILURE;
00598 }
00599 
00600 
00601 
00602 PRBool nsMacUnicodeFontInfo::HasGlyphFor(PRUnichar aChar)
00603 {
00604   if (0xfffd == aChar)
00605     return PR_FALSE;
00606 
00607   if (!gCCMap) 
00608     gCCMap = InitGlobalCCMap();
00609 
00610   NS_ASSERTION(gCCMap, "cannot init global ccmap");
00611     
00612   if (gCCMap)
00613     return CCMAP_HAS_CHAR(gCCMap, aChar);
00614 
00615   return PR_FALSE;
00616 }
00617 
00618 void nsMacUnicodeFontInfo::FreeGlobals()
00619 {    
00620   NS_IF_RELEASE(gFontEncodingProperties);
00621   NS_IF_RELEASE(gCharsetManager);
00622 
00623   delete gFontMaps;
00624   if (gCCMap)
00625     FreeCCMap(gCCMap);  
00626 }