Back to index

lightning-sunbird  0.9+nobinonly
nsFT2FontCatalog.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ex: set tabstop=8 softtabstop=2 shiftwidth=2 expandtab: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Brian Stell <bstell@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "gfx-config.h"
00041 #include "nsFT2FontCatalog.h"
00042 #include "nsFontDebug.h"
00043 
00044 PRUint32 gFontDebug = 0 | NS_FONT_DEBUG_FONT_SCAN;
00045 
00046 #if (defined(MOZ_ENABLE_FREETYPE2))
00047 
00048 #include <stdio.h>
00049 #include <stdlib.h>
00050 #include <string.h>
00051 #include <unistd.h>
00052 #include <sys/stat.h>
00053 #include <sys/time.h>
00054 #include <dirent.h>
00055 #include "nsAppDirectoryServiceDefs.h"
00056 #include "nsLocalFile.h"
00057 #include "nsIEnumerator.h"
00058 #include "nsITimelineService.h"
00059 #include "nsArray.h"
00060 
00061 //
00062 // Short overview:
00063 //  This code is here primarily to solve this problem: getting the list
00064 //  of valid glyphs in a TrueType font is very expensive when using
00065 //  the FreeType2 library. To solve this problem this code looks for
00066 //  a pre-built summary file in the font dir. If this font summary
00067 //  file is missing it is built and stored in the font dir if possible
00068 //  so it need not be generated by every user. If the user cannot write
00069 //  in the font dir the summary is stored in a per-user dir 
00070 //  (ie: $HOME/.mozilla/fontsummaries).
00071 //
00072 // The routines are in alphabetic order to assist people reading
00073 // this code printed on paper in finding the routines.
00074 //
00075 // The interesting high level entry points are:
00076 //
00077 // nsFT2FontCatalog::InitGlobals();
00078 //   Called during startup to read (and update) the font catalog(s).
00079 //
00080 // nsFT2FontCatalog::GetFontNames();
00081 //   Called when the font code is looking for a font.
00082 //
00083 // Some interesting low level entry points are:
00084 //
00085 // nsFT2FontCatalog::NewFceFromFontFile();
00086 //   Called to get a TrueType font summary.
00087 //   Uses FreeType2 to actually open the font file.
00088 //   This checks for invalid glyphs so this can take a while.
00089 //   The summary will later be stored in the disk font catalog.
00090 //
00091 // nsFT2FontCatalog::NewFceFromSummary();
00092 //   Called to get the TrueType font summary from the disk font catalog.
00093 //
00094 
00095 // Solaris is missing a prototype for ctime
00096 extern "C" {char *ctime(const time_t *timep);}
00097 
00098 #include <ft2build.h>
00099 #include FT_GLYPH_H
00100 #include FT_FREETYPE_H
00101 #include FT_TRUETYPE_TABLES_H
00102 #include FT_TRUETYPE_IDS_H
00103 
00104 // these should be static but the compilier complains
00105 extern nsFontVendorName sVendorNamesList[];
00106 extern nsulCodePageRangeLanguage    ulCodePageRange1Language[];
00107 extern nsulCodePageRangeLanguage    ulCodePageRange2Language[];
00108 
00109 nsHashtable* nsFT2FontCatalog::sVendorNames = nsnull;
00110 nsIPref*     nsFT2FontCatalog::sPref = nsnull;
00111 
00112 #endif
00113 
00114 //
00115 // Implementation of Interfaces nsIFontCatalogService
00116 //
00117 NS_IMPL_ISUPPORTS1(nsFT2FontCatalog, nsIFontCatalogService)
00118 
00119 nsFT2FontCatalog::nsFT2FontCatalog()
00120 #ifdef MOZ_ENABLE_FREETYPE2
00121  : mFontCatalog(nsnull),
00122    mRange1Language(nsnull),
00123    mRange2Language(nsnull)
00124 #endif
00125 {
00126 #if (defined(MOZ_ENABLE_FREETYPE2))
00127   nsresult rv;
00128   mAvailableFontCatalogService = PR_FALSE;
00129 
00130   mFt2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv);
00131   if (NS_FAILED(rv)) {
00132     // FreeType is not available
00133     return;
00134   }
00135 
00136   FT_Library lib;
00137   mFt2->GetLibrary(&lib);
00138   if (!lib) {
00139     // FreeType is not available
00140     return;
00141   }
00142 
00143   if (!InitGlobals(lib)) {
00144     // Font Catalog Service is not available
00145     return;
00146   }
00147   mAvailableFontCatalogService = PR_TRUE;
00148 #endif
00149 }
00150 
00151 nsFT2FontCatalog::~nsFT2FontCatalog()
00152 {
00153 #if (defined(MOZ_ENABLE_FREETYPE2))
00154   FreeGlobals();
00155 #endif
00156 }
00157 
00158 NS_IMETHODIMP
00159 nsFT2FontCatalog::GetFontCatalogEntries(const nsACString & aFamilyName,
00160                                         const nsACString & aLanguage,
00161                                         PRUint16 aWeight,
00162                                         PRUint16 aWidth,
00163                                         PRUint16 aSlant,
00164                                         PRUint16 aSpacing,
00165                                         nsIArray **_retval)
00166 {
00167 #if (!defined(MOZ_ENABLE_FREETYPE2))
00168   *_retval = nsnull;
00169   return NS_OK;
00170 #else
00171   if (mAvailableFontCatalogService == PR_FALSE) {
00172     *_retval = nsnull;
00173     return NS_OK;
00174   }
00175   
00176   nsFontCatalog *fc = NewFontCatalog();
00177   if (!fc)
00178     return NS_ERROR_OUT_OF_MEMORY;
00179 
00180   GetFontNames(aFamilyName, aLanguage, aWeight, aWidth, aSlant, aSpacing, fc);
00181   nsCOMPtr<nsITrueTypeFontCatalogEntry> aFce;
00182   nsCOMPtr<nsISupports> genericFce;
00183   nsCOMPtr<nsIMutableArray> entries;
00184   NS_NewArray(getter_AddRefs(entries));
00185   if (!entries)
00186     return NS_ERROR_OUT_OF_MEMORY;
00187   
00188   int i;
00189   for (i = 0; i < fc->numFonts; i++) {
00190     aFce = nsFreeTypeGetFaceID(fc->fonts[i]);
00191     genericFce = do_QueryInterface(aFce);
00192     entries->InsertElementAt(genericFce, 0, PR_FALSE);
00193   }
00194  
00195   free(fc->fonts);
00196   free(fc);
00197   *_retval = entries;
00198   NS_ADDREF(*_retval);
00199 #endif
00200   return NS_OK;
00201 }
00202 
00203 //--------------------------------------------------
00204 
00205 #if (defined(MOZ_ENABLE_FREETYPE2))
00206 
00207 void
00208 nsFT2FontCatalog::AddDir(nsDirCatalog *dc, nsDirCatalogEntry *dir)
00209 {
00210   if (dc->numDirs >= dc->numSlots) {
00211     dc->numSlots += PR_MAX(1, PR_MIN(dc->numDirs, 128));
00212     dc->dirs = (nsDirCatalogEntry **)realloc(dc->dirs,
00213                            dc->numSlots*sizeof(nsDirCatalogEntry *));
00214   }
00215   dc->dirs[dc->numDirs] = dir;
00216   dc->numDirs++;
00217 }
00218 
00219 PRBool
00220 nsFT2FontCatalog::AddFceIfCurrent(const char *aFileName, 
00221                                   nsHashtable* aFceHash,
00222                                   PRInt64 aFileModTime,
00223                                   nsFontCatalog *aFontCatalog)
00224 {
00225   int i;
00226   nsCStringKey key(aFileName);
00227 
00228   //
00229   // get it from the font summaries
00230   //
00231   nsFontCatalogEntry *fce = (nsFontCatalogEntry *)aFceHash->Get(&key);
00232   if (!fce)
00233     return PR_FALSE;
00234 
00235   //
00236   // Check the time
00237   //
00238   PRInt64 fs_modtime = fce->mMTime;
00239   LL_DIV(aFileModTime, aFileModTime, 1000); // microsec -> millisec
00240   if (LL_NE(aFileModTime, fs_modtime))
00241     return PR_FALSE;
00242 
00243   //
00244   // Move to the font catalog
00245   //
00246   aFceHash->Remove(&key);
00247   AddFont(aFontCatalog, fce);
00248 
00249   //
00250   // get other faces of the font
00251   //
00252   for (i=1; i<fce->mNumFaces; i++) {
00253     nsCAutoString key_str(aFileName);
00254     // We use this hash when we are checking the files' timestamp.
00255     // Since we do not want to open the file we cannot use the
00256     // ttc face names (we would need to open the font to get that).
00257     // So for the key we append a slash and number to give us a unique key
00258     // for each ttc face.
00259     char buf[20];
00260     sprintf(buf, "/%d", i);
00261     key_str.Append(buf);
00262     key = key_str;
00263     fce = (nsFontCatalogEntry *)aFceHash->Get(&key);
00264     NS_ASSERTION(fce, "additional font faces missing");
00265     if (!fce) {
00266       FONT_CATALOG_PRINTF(("missing font face %d, %s", i, aFileName));
00267       return PR_FALSE;
00268     }
00269     aFceHash->Remove(&key);
00270     AddFont(aFontCatalog, fce);
00271   }
00272 
00273   return PR_TRUE;
00274 }
00275 
00276 void
00277 nsFT2FontCatalog::AddFont(nsFontCatalog *fc, nsFontCatalogEntry *fce)
00278 {
00279   if (fc->numFonts >= fc->numSlots) {
00280     fc->numSlots += PR_MAX(1, PR_MIN(fc->numFonts, 128));
00281     fc->fonts = (nsFontCatalogEntry **)realloc(fc->fonts,
00282                            fc->numSlots*sizeof(nsFontCatalogEntry *));
00283   }
00284   fc->fonts[fc->numFonts] = fce;
00285   fc->numFonts++;
00286 }
00287 
00288 int
00289 nsFT2FontCatalog::CheckFontSummaryVersion(nsNameValuePairDB *aDB)
00290 {
00291   const char *type, *name, *value;
00292   unsigned int num, major, minor, rev;
00293   int result = FC_FILE_GARBLED;
00294 
00295   if (aDB->GetNextGroup(&type, FONT_SUMMARY_VERSION_TAG)) {
00296     while (aDB->GetNextElement(&name, &value) > 0) {
00297       if (*name == '\0') // ignore comments
00298         continue;
00299       if (strcmp(name, "Version")==0) {
00300         num = sscanf(value, "%u.%u.%u", &major, &minor, &rev);
00301         if (num != 3) {
00302           FONT_CATALOG_PRINTF(("failed to parse version number (%s)", value));
00303           return result;
00304         }
00305         // FONT_SUMMARY_VERSION_MAJOR
00306         // It is presumed that major versions are not backwards compatibile.
00307         if (major == FONT_SUMMARY_VERSION_MAJOR)
00308           result = FC_FILE_OKAY;
00309         else
00310           FONT_CATALOG_PRINTF(("version major %d != %d", major, 
00311                                FONT_SUMMARY_VERSION_MAJOR));
00312 
00313         // FONT_SUMMARY_VERSION_MINOR
00314         // If there is a backwards compatibility with different
00315         // minor versions put the test here.
00316 
00317         // FONT_SUMMARY_VERSION_REV
00318         // if there should not be backwards compatibility issues
00319         // with different revisions.
00320       }
00321     }
00322   }
00323 
00324   return result;
00325 }
00326 
00327 #ifdef DEBUG
00328 void
00329 nsFT2FontCatalog::DumpFontCatalog(nsFontCatalog *fc)
00330 {
00331   int i;
00332   for (i=0; i<fc->numFonts; i++) {
00333     nsFontCatalogEntry *fce;
00334     fce = fc->fonts[i];
00335     if (!fce->mFlags&FCE_FLAGS_ISVALID)
00336       continue;
00337     DumpFontCatalogEntry(fce);
00338   }
00339 }
00340 #endif
00341 
00342 #ifdef DEBUG
00343 void
00344 nsFT2FontCatalog::DumpFontCatalogEntry(nsFontCatalogEntry *fce)
00345 {
00346   printf("  fce->mFontFileName      = %s\n", fce->mFontFileName);
00347   printf("    fce->mMTime           = %ld %s", fce->mMTime,ctime(&fce->mMTime));
00348   printf("    fce->mFlags           = 0x%08x\n", fce->mFlags);
00349   printf("    fce->mFaceIndex       = %d\n", fce->mFaceIndex);
00350   printf("    fce->mNumFaces        = %d\n", fce->mNumFaces);
00351   printf("    fce->mFontType        = %s\n", fce->mFontType);
00352   printf("    fce->mFamilyName      = %s\n", fce->mFamilyName);
00353   printf("    fce->mStyleName       = %s\n", fce->mStyleName);
00354   printf("    fce->mNumGlyphs       = %d\n", fce->mNumGlyphs);
00355   printf("    fce->mNumUsableGlyphs = %d\n", fce->mNumUsableGlyphs);
00356   printf("    fce->mFaceFlags       = 0x%08lx\n", fce->mFaceFlags);
00357   printf("    fce->mStyleFlags      = 0x%08lx\n", fce->mStyleFlags);
00358   printf("                            style: ");
00359   printf("%s, ", fce->mStyleFlags & FT_STYLE_FLAG_ITALIC ?
00360                          "italic" : "roman");
00361   printf("%s", fce->mStyleFlags & FT_STYLE_FLAG_BOLD ?
00362                          "bold" : "regular");
00363   printf("\n");
00364   printf("    fce->mWeight          = %d\n", fce->mWeight);
00365   printf("    fce->mWidth           = %d\n", fce->mWidth);
00366   printf("    lang groups (0x%08lx, 0x%08lx): ",
00367                fce->mCodePageRange1, fce->mCodePageRange2);
00368 
00369   if ((fce->mCodePageRange1 == 0)
00370       && (fce->mCodePageRange2 == 0)) {
00371     printf("guessing latin1 (%d glyphs)", fce->mNumGlyphs);
00372     if (fce->mNumGlyphs > 300) {
00373       printf("why no lang groups for %s (%s) and so many (%d) glyphs \n",
00374                  fce->mFamilyName, fce->mFontFileName, fce->mNumGlyphs);
00375     }
00376   }
00377 
00378   if ((fce->mCodePageRange1 & TT_OS2_CPR1_LATIN1)
00379       || (fce->mCodePageRange1 & TT_OS2_CPR1_MAC_ROMAN)
00380       || (fce->mCodePageRange2 & TT_OS2_CPR2_WE_LATIN1)
00381       || (fce->mCodePageRange2 & TT_OS2_CPR2_US))
00382     printf("latin1 (iso8859-1), ");
00383 
00384   if ((fce->mCodePageRange1 & TT_OS2_CPR1_LATIN2)
00385       || (fce->mCodePageRange2 & TT_OS2_CPR2_LATIN2))
00386     printf("latin2 (iso8859-2), ");
00387 
00388   if ((fce->mCodePageRange1 & TT_OS2_CPR1_CYRILLIC)
00389       || (fce->mCodePageRange2 & TT_OS2_CPR2_CYRILLIC))
00390     printf("cyrillic (iso8859-5), ");
00391 
00392   if ((fce->mCodePageRange1 & TT_OS2_CPR1_GREEK)
00393       || (fce->mCodePageRange2 & TT_OS2_CPR2_GREEK)
00394       || (fce->mCodePageRange2 & TT_OS2_CPR2_GREEK_437G))
00395     printf("greek (iso8859-7), ");
00396 
00397   if ((fce->mCodePageRange1 & TT_OS2_CPR1_TURKISH)
00398       || (fce->mCodePageRange2 & TT_OS2_CPR2_TURKISH))
00399     printf("turkish (iso8859-9), ");
00400 
00401   if ((fce->mCodePageRange1 & TT_OS2_CPR1_HEBREW)
00402       || (fce->mCodePageRange2 & TT_OS2_CPR2_HEBREW))
00403     printf("hebrew (iso8859-8), ");
00404 
00405   if ((fce->mCodePageRange1 & TT_OS2_CPR1_ARABIC)
00406       || (fce->mCodePageRange2 & TT_OS2_CPR2_ARABIC)
00407       || (fce->mCodePageRange2 & TT_OS2_CPR2_ARABIC_708))
00408     printf("arabic (iso8859-6), ");
00409 
00410   if ((fce->mCodePageRange1 & TT_OS2_CPR1_BALTIC)
00411       || (fce->mCodePageRange2 & TT_OS2_CPR2_BALTIC))
00412     printf("baltic (iso8859-4), ");
00413 
00414   if (fce->mCodePageRange1 & TT_OS2_CPR1_VIETNAMESE)
00415     printf("vietnamese (viscii1.1-1), ");
00416 
00417   if (fce->mCodePageRange1 & TT_OS2_CPR1_THAI)
00418     printf("thai (tis620.2533-1), ");
00419 
00420   if (fce->mCodePageRange1 & TT_OS2_CPR1_JAPANESE)
00421     printf("japanese (jisx0208.1990-0), ");
00422 
00423   if (fce->mCodePageRange1 & TT_OS2_CPR1_CHINESE_SIMP)
00424     printf("simplified Chinese (gb2312.1980-1), ");
00425 
00426   if ((fce->mCodePageRange1 & TT_OS2_CPR1_KO_WANSUNG)
00427       || (fce->mCodePageRange1 & TT_OS2_CPR1_KO_JOHAB))
00428     printf("korean (ksc5601.1992-3), ");
00429 
00430   if (fce->mCodePageRange1 & TT_OS2_CPR1_CHINESE_TRAD)
00431     printf("traditional Chinese (big5-0), ");
00432 
00433   if (fce->mCodePageRange1 & TT_OS2_CPR1_SYMBOL)
00434     printf("symbol (misc-fontspecific), ");
00435 
00436   if (fce->mCodePageRange2 & TT_OS2_CPR2_RUSSIAN)
00437     printf("russian (koi8-r), ");
00438 
00439   if (fce->mCodePageRange2 & TT_OS2_CPR2_NORDIC)
00440     printf("nordic (iso8859-10), ");
00441 
00442   if (fce->mCodePageRange2 & TT_OS2_CPR2_CA_FRENCH)
00443     printf("canadian french (iso8859-1), ");
00444 
00445   if (fce->mCodePageRange2 & TT_OS2_CPR2_ICELANDIC)
00446     printf("icelandic (iso8859-1), ");
00447 
00448   if (fce->mCodePageRange2 & TT_OS2_CPR2_PORTUGESE)
00449     printf("portugese (iso8859-1), ");
00450 
00451   printf("\n");
00452 
00453   printf("    fce->mVendorID        = %4s\n", fce->mVendorID);
00454   printf("    fce->mFoundryName     = %s\n", fce->mFoundryName);
00455   printf("    fce->mEmbeddedBitmapHeights=");
00456   for (int i=0; i<fce->mNumEmbeddedBitmaps; i++)
00457     printf("%d,", fce->mEmbeddedBitmapHeights[i]);
00458   printf("\n");
00459   printCCMap(fce->mCCMap);
00460 }
00461 #endif
00462 
00463 void
00464 nsFT2FontCatalog::FixUpFontCatalog(nsFontCatalog *fc)
00465 {
00466   int i;
00467   for (i=0; i<fc->numFonts; i++) {
00468     nsFontCatalogEntry *fce;
00469     fce = fc->fonts[i];
00470     if (!fce->mFlags&FCE_FLAGS_ISVALID)
00471       continue;
00472     // some TrueType fonts seem to have weights in the 1 to 9 range
00473     if ((fce->mWeight>=1) && (fce->mWeight<=9)) {
00474       if (mIsNewCatalog)
00475         FONT_CATALOG_PRINTF(("change weight from %d to %d, %s",
00476                            fce->mWeight, fce->mWeight*100, fce->mFamilyName));
00477       fce->mWeight *= 100;
00478     }
00479     if ((fce->mWeight<100) || (fce->mWeight>900)) {
00480       FONT_CATALOG_PRINTF(("invalid weight %d, %s", fce->mWeight, 
00481                             fce->mFamilyName));
00482       fce->mFlags &= ~FCE_FLAGS_ISVALID;
00483       continue;
00484     }
00485     if (fce->mWidth>8) {
00486       FONT_CATALOG_PRINTF(("limit width from %d to 8, %s", fce->mWidth, 
00487                            fce->mFamilyName));
00488       fce->mWidth = 8;
00489     }
00490     nsCAutoString familyName(fce->mFamilyName);
00491     free((void*)fce->mFamilyName);
00492     ToLowerCase(familyName);
00493     // nsFontMetricsGTK (like XLFD) does not allow a dash in the name
00494     familyName.ReplaceChar('-', ' ');
00495     fce->mFamilyName = strdup(familyName.get());
00496     if (!fce->mFamilyName) {
00497       fce->mFlags &= ~FCE_FLAGS_ISVALID;
00498       continue;
00499     }
00500 
00501     nsCAutoString vendorID(fce->mVendorID);
00502     ToLowerCase(vendorID);
00503     vendorID.StripChars(" ");
00504     nsCStringKey key(vendorID);
00505     const char *vendorStr = (const char *)sVendorNames->Get(&key);
00506     if (!vendorStr) {
00507       if (fce->mVendorID[0])
00508         vendorStr = fce->mVendorID;
00509       else
00510         vendorStr = "<unknown>";
00511     }
00512     nsCAutoString vendorName(vendorStr);
00513     ToLowerCase(vendorName);
00514     fce->mFoundryName = strdup(vendorName.get());
00515     if (!fce->mFoundryName) {
00516       fce->mFlags &= ~FCE_FLAGS_ISVALID;
00517       continue;
00518     }
00519     if ((fce->mCodePageRange1==0) && (fce->mCodePageRange2==0)
00520         && !(fce->mFlags&FCE_FLAGS_SYMBOL)) {
00521       // no lang group set so try guessing Latin1
00522       NS_ASSERTION(fce->mNumGlyphs<=300,
00523                 "font has no lang group bits set AND has over 300 glyphs");
00524       if (fce->mNumGlyphs>300)
00525         FONT_CATALOG_PRINTF(("no CodePageRange bits but %d glyphs, %s",
00526                     fce->mNumGlyphs, fce->mFamilyName));
00527       fce->mCodePageRange1 |= TT_OS2_CPR1_LATIN1;
00528     }
00529   }
00530 }
00531 
00532 PRBool
00533 nsFT2FontCatalog::FreeFceHashEntry(nsHashKey* aKey, void* aData, void* aClosure)
00534 {
00535   nsFontCatalogEntry *fce = (nsFontCatalogEntry *)aData;
00536   FreeFontCatalogEntry(fce);
00537   return PR_TRUE;
00538 }
00539 
00540 void
00541 nsFT2FontCatalog::FreeFontCatalog(nsFontCatalog *fc)
00542 {
00543   int i;
00544   for (i=0; i<fc->numFonts; i++) {
00545     nsFontCatalogEntry *fce;
00546     fce = fc->fonts[i];
00547     FreeFontCatalogEntry(fce);
00548   }
00549   free(fc->fonts);
00550   free(fc);
00551 }
00552 
00553 void
00554 nsFT2FontCatalog::FreeDirCatalog(nsDirCatalog *dc)
00555 {
00556   int i;
00557   for (i=0; i<dc->numDirs; i++) {
00558     nsDirCatalogEntry *dce;
00559     dce = dc->dirs[i];
00560     FreeDirCatalogEntry(dce);
00561   }
00562   free(dc->dirs);
00563   free(dc);
00564 }
00565 
00566 void
00567 nsFT2FontCatalog::FreeDirCatalogEntry(nsDirCatalogEntry *dce)
00568 {
00569   if (!dce) {
00570     NS_ASSERTION(dce, "dce is null");
00571     return;
00572   }
00573 
00574   FREE_IF(dce->mDirName);
00575   free(dce);
00576 }
00577 
00578 
00579 void
00580 nsFT2FontCatalog::FreeFontCatalogEntry(nsFontCatalogEntry *fce)
00581 {
00582   if (!fce) {
00583     NS_ASSERTION(fce, "fce is null");
00584     return;
00585   }
00586 
00587   FREE_IF(fce->mFontFileName);
00588   FREE_IF(fce->mFontType);
00589   FREE_IF(fce->mFamilyName);
00590   FREE_IF(fce->mStyleName);
00591   FREE_IF(fce->mFoundryName);
00592   FREE_IF(fce->mEmbeddedBitmapHeights);
00593   if (fce->mCCMap)
00594     FreeCCMap(fce->mCCMap);
00595   free(fce);
00596 }
00597 
00598 void
00599 nsFT2FontCatalog::FreeGlobals()
00600 {
00601   if (mFontCatalog) {
00602     FreeFontCatalog(mFontCatalog);
00603     mFontCatalog = nsnull;
00604   }
00605 
00606   // sVendorNames elements are not alloc'd so no need call Reset
00607   delete sVendorNames;
00608  
00609   delete mRange1Language;
00610   delete mRange2Language;
00611 
00612   NS_IF_RELEASE(sPref);
00613 }
00614 
00615 void
00616 nsFT2FontCatalog::GetDirsPrefEnumCallback(const char* aName, void* aClosure)
00617 {
00618   nsDirCatalog *dirCatalog = (nsDirCatalog *)aClosure;
00619   nsDirCatalogEntry *dce;
00620   dce = (nsDirCatalogEntry *)calloc(1, sizeof(nsDirCatalogEntry));
00621   if (!dce)
00622     return;
00623   // native charset?!
00624   sPref->CopyCharPref(aName, (char **)&dce->mDirName);
00625   if (!dce->mDirName)
00626     return;
00627   AddDir(dirCatalog, dce);
00628 }
00629 
00630 PRInt32 *
00631 nsFT2FontCatalog::GetEmbeddedBitmapHeights(nsFontCatalogEntry *aFce)
00632 {
00633   return aFce->mEmbeddedBitmapHeights;
00634 }
00635 
00636 PRInt32
00637 nsFT2FontCatalog::GetFaceIndex(nsFontCatalogEntry *aFce)
00638 {
00639   return aFce->mFaceIndex;
00640 }
00641 
00642 const char*
00643 nsFT2FontCatalog::GetFamilyName(nsFontCatalogEntry *aFce)
00644 {
00645   return aFce->mFamilyName;
00646 }
00647 
00648 const char*
00649 nsFT2FontCatalog::GetFileName(nsFontCatalogEntry *aFce)
00650 {
00651   return aFce->mFontFileName;
00652 }
00653 
00654 int
00655 nsFT2FontCatalog::GetFontCatalog(FT_Library lib, nsFontCatalog *aFontCatalog, 
00656                                  nsDirCatalog *aOldDirCatalog)
00657 {
00658   int i;
00659   nsresult rv;
00660   nsCAutoString font_summaries_dir_path;
00661   nsCAutoString font_download_dir_path;
00662   PRBool exists;
00663   nsCOMPtr<nsIFile> font_summaries_dir, font_download_dir;
00664 
00665   if (lib) {
00666     //
00667     // Get the dir for downloaded fonts
00668     //
00669     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(font_download_dir));
00670     if (NS_FAILED(rv))
00671       goto cleanup_and_return;
00672 
00673     rv = font_download_dir->AppendNative(FONT_DOWNLOAD_SUBDIR);
00674     if (NS_FAILED(rv))
00675       goto cleanup_and_return;
00676     exists = PR_FALSE;
00677     rv = font_download_dir->Exists(&exists);
00678     if (NS_FAILED(rv))
00679       goto cleanup_and_return;
00680     
00681     if (!exists) {
00682       rv = font_download_dir->Create(nsIFile::DIRECTORY_TYPE, 0775);
00683       if (NS_FAILED(rv))
00684         goto cleanup_and_return;
00685     }
00686     rv = font_download_dir->GetNativePath(font_download_dir_path);
00687     if (NS_FAILED(rv))
00688       goto cleanup_and_return;
00689 
00690     //
00691     // Get the user dir for font catalogs
00692     //
00693     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(font_summaries_dir));
00694     if (NS_FAILED(rv))
00695       goto cleanup_and_return;
00696 
00697     rv = font_summaries_dir->AppendNative(FONT_DOWNLOAD_SUBDIR);
00698     if (NS_FAILED(rv))
00699       goto cleanup_and_return;
00700     rv = font_summaries_dir->AppendNative(FONT_SUMMARIES_SUBDIR);
00701     if (NS_FAILED(rv))
00702       goto cleanup_and_return;
00703     exists = PR_FALSE;
00704     rv = font_summaries_dir->Exists(&exists);
00705     if (NS_FAILED(rv))
00706       goto cleanup_and_return;
00707     
00708     if (!exists) {
00709       rv = font_summaries_dir->Create(nsIFile::DIRECTORY_TYPE, 0775);
00710       if (NS_FAILED(rv))
00711         goto cleanup_and_return;
00712     }
00713     rv = font_summaries_dir->GetNativePath(font_summaries_dir_path);
00714     if (NS_FAILED(rv))
00715       goto cleanup_and_return;
00716 
00717     //
00718     // Get the font summaries for the public font dirs
00719     //
00720     for (i=0; i<aOldDirCatalog->numDirs; i++) {
00721       HandleFontDir(lib, aFontCatalog, font_summaries_dir_path,
00722                     nsDependentCString(aOldDirCatalog->dirs[i]->mDirName));
00723     }
00724 
00725     //
00726     // Get the font summaries for the downloaded/private font dir
00727     //
00728     HandleFontDir(lib, aFontCatalog, font_summaries_dir_path, font_download_dir_path);
00729   }
00730 
00731   return 0;
00732 
00733 cleanup_and_return:
00734   FONT_CATALOG_PRINTF(("nsFT2FontCatalog::GetFontCatalog failed"));
00735   return -1;
00736 }
00737 
00738 void
00739 nsFT2FontCatalog::GetFontNames(const nsACString & aFamilyName,
00740                                const nsACString & aLanguage,
00741                                PRUint16           aWeight,
00742                                PRUint16           aWidth,
00743                                PRUint16           aSlant,
00744                                PRUint16           aSpacing,
00745                                nsFontCatalog*     aFC)
00746 {
00747   int i;
00748   PRUint16 min_weight = PR_MAX(0, aWeight-125);
00749   PRUint16 max_weight = PR_MIN(999, aWeight+125);
00750   nsCAutoString familyName, language;
00751   FONT_CATALOG_PRINTF(("looking for FreeType font matching"));
00752 
00753   ToLowerCase(aFamilyName, familyName);
00754   ToLowerCase(aLanguage, language);
00755   
00756   FONT_CATALOG_PRINTF(("familyName=%s; language=%s; "
00757                        "weight=%d; width=%d; slant=%d; spacing=%d",
00758                        familyName.get(), language.get(),
00759                        aWeight, aWidth, aSlant, aSpacing));
00760 
00761   unsigned long bit1 = GetRangeLanguage(language, CPR1);
00762   unsigned long bit2 = GetRangeLanguage(language, CPR2);
00763 
00764   PRUint16 italicBit = 0;
00765   switch (aSlant) {
00766     case kFCSlantRoman:
00767       break;
00768     case kFCSlantItalic:
00769     case kFCSlantOblique:
00770     case kFCSlantReverseItalic:
00771     case kFCSlantReverseOblique:
00772       italicBit = 1;
00773       break;
00774     default:
00775       break;
00776   }
00777   
00778   PRUint16 monoBit = 0;
00779   switch (aSpacing) {
00780     case kFCSpacingMonospace:
00781       monoBit = 0;
00782       break;
00783     case kFCSpacingProportional:
00784       monoBit = 1;
00785       break;
00786     default:
00787       break;
00788   }
00789   
00790   /* column headers for the debug output*/
00791   FONT_CATALOG_PRINTF(("%s\t%-20s\t%-8s\t%-8s\t%-8s%-8s%-8s\t%-8s\t",
00792                         "mFlags",
00793                         "mFamilyName",
00794                         "mCodePageRange1",
00795                         "mCodePageRange2",
00796                         "mWeight",
00797                         "mWidth",
00798                         "mStyleFlags",
00799                         "fce->mFaceFlags"));
00800 
00801   for (i=0; i<mFontCatalog->numFonts; i++) {
00802     nsFontCatalogEntry *fce = mFontCatalog->fonts[i];
00803     // not all "fce" are valid
00804     if (!fce->mFlags&FCE_FLAGS_ISVALID)
00805       continue;
00806     // family
00807     if (!familyName.IsEmpty() && !familyName.Equals(fce->mFamilyName))
00808       continue;
00809     // language
00810     if (!language.IsEmpty() &&
00811         !((fce->mCodePageRange1 & bit1) || (fce->mCodePageRange2 & bit2)))
00812       continue;
00813     // weight (the meaning is not well defined so allow some variance)
00814     if ((aWeight != kFCWeightAny)
00815          && ((fce->mWeight < min_weight) || (fce->mWeight > max_weight)))
00816       continue;
00817     // width
00818     if ((aWidth != kFCWidthAny) && (aWidth != fce->mWidth))
00819       continue;
00820     // slant
00821     if ((aSlant != kFCSlantAny)
00822          && !((fce->mStyleFlags & FT_STYLE_FLAG_ITALIC) == italicBit))
00823       continue;
00824     // spacing
00825     if ((aSpacing != kFCSpacingAny)
00826          && !((fce->mFaceFlags & FT_FACE_FLAG_FIXED_WIDTH) == monoBit))
00827       continue;
00828     // match all patterns
00829     FONT_CATALOG_PRINTF(("%0x\t%-20s\t%08lx\t%08lx\t%i\t%i\t%08lx\t%08lx",
00830                         fce->mFlags,
00831                         fce->mFamilyName,
00832                         fce->mCodePageRange1,
00833                         fce->mCodePageRange2,
00834                         fce->mWeight,
00835                         fce->mWidth,
00836                         fce->mStyleFlags,
00837                         fce->mFaceFlags));
00838     AddFont(aFC, fce);
00839   }
00840   return;
00841 }
00842 
00843 PRBool
00844 nsFT2FontCatalog::GetFontSummaryName(const nsACString &aFontDirName,      // native charset
00845                                      const nsACString &aFontSummariesDir, // native charset
00846                                      nsACString &aFontSummaryFileName,
00847                                      nsACString 
00848                                                &aFallbackFontSummaryFileName)
00849 {
00850   int error;
00851   struct stat file_info;
00852   PRBool exists = PR_FALSE;
00853   PRBool public_dir_writable = PR_FALSE;
00854   PRBool public_summary_writable = PR_FALSE;
00855   nsresult rv;
00856   nsCOMPtr<nsILocalFile> font_dir;
00857 
00858   //
00859   // see if we should use the "public" one in the font dir itself
00860   // or the "private" one in our $HOME/.mozilla/fontsummaries dir
00861   //
00862   font_dir = new nsLocalFile();
00863   font_dir->InitWithNativePath(aFontDirName);
00864   rv = font_dir->IsWritable(&public_dir_writable);
00865   if (NS_SUCCEEDED(rv) && public_dir_writable) {
00866     FONT_CATALOG_PRINTF(("can write \"%s\"", PromiseFlatCString(aFontDirName).get()));
00867     nsCOMPtr<nsILocalFile> summary_file = new nsLocalFile();
00868     summary_file->InitWithNativePath(aFontDirName);
00869     summary_file->AppendNative(PUBLIC_FONT_SUMMARY_NAME);
00870     nsCAutoString font_summary_path;
00871     summary_file->GetNativePath(font_summary_path);
00872     FONT_CATALOG_PRINTF(("font_summary_path = \"%s\"", font_summary_path.get()));
00873     rv = summary_file->Exists(&exists);
00874     if (NS_SUCCEEDED(rv)) {
00875       if (!exists) {
00876         public_summary_writable = PR_TRUE;
00877         aFontSummaryFileName = font_summary_path;
00878       }
00879       else {
00880         FONT_CATALOG_PRINTF(("font summary \"%s\" exists", font_summary_path.get()));
00881         rv = summary_file->IsWritable(&public_summary_writable);
00882         if (NS_SUCCEEDED(rv) && public_summary_writable) {
00883           FONT_CATALOG_PRINTF(("font summary \"%s\" is writable", 
00884                                font_summary_path.get()));
00885           public_summary_writable = PR_TRUE;
00886           aFontSummaryFileName = font_summary_path;
00887         }
00888       }
00889     }
00890   }
00891 
00892   if (!public_summary_writable) {
00893     //
00894     // Generate the private font summary name from:
00895     //  1) the user's product directory
00896     //  2) the font dir's parent dir's device/inode
00897     //  3) the font dir's name in that dir
00898     // file name = 
00899     // <last part of the path>.d<device number>.ndb
00900     // eg: for:
00901     // user's product dir "/home/bstell/.mozilla/fontsummaries"
00902     // the font dir "/home/bstell/tt_font"
00903     // where /home/bstell is inode 1234 on device 3,2
00904     // the name would be:
00905     //
00906     //   /home/bstell/.mozilla/fontsummaries/tt_font.d0302.i1234.ndb
00907     //
00908 
00909     //
00910     // Split the parent dir and file name
00911     //
00912     PRInt32 slash = 0, last_slash = -1;
00913     // RFindChar not coded so do it by hand
00914     while ((slash=aFontDirName.FindChar('/', slash))>=0) {
00915       last_slash = slash;
00916       slash++;
00917     }
00918     if (last_slash < 0) {
00919       FONT_CATALOG_PRINTF(("did not find a \"/\" in %s", 
00920                            PromiseFlatCString(aFontDirName).get())); 
00921       return PR_FALSE;
00922     }
00923     int right_len =  aFontDirName.Length() - last_slash - 1;
00924     nsCAutoString parent_dir(Substring(aFontDirName, 0, last_slash));
00925     nsCAutoString font_dir_name_tail(Substring(aFontDirName,
00926                                                last_slash+1, right_len));
00927     //
00928     // Get the parent dir's device and inode
00929     //
00930     error = stat(PromiseFlatCString(parent_dir).get(), &file_info);
00931     if (error) {
00932       FONT_CATALOG_PRINTF(("failed to stat %s", 
00933                 PromiseFlatCString(parent_dir).get()));
00934       return PR_FALSE;
00935     }
00936 
00937     int dev = file_info.st_dev;
00938     int inode = file_info.st_ino;
00939     FONT_CATALOG_PRINTF(("parent dir dev = %04x, inode = %d", dev, inode));
00940     char buf[64];
00941     sprintf(buf, ".d%04x.i%d", dev, inode);
00942     font_dir_name_tail.Append(buf);
00943 
00944     //
00945     // Build the font summary name
00946     //
00947     aFontSummaryFileName = aFontSummariesDir;
00948     aFontSummaryFileName.Append("/");
00949     aFontSummaryFileName.Append(font_dir_name_tail);
00950     aFontSummaryFileName.Append(FONT_SUMMARIES_EXTENSION);
00951 
00952     //
00953     // Build the backup Font Summary name
00954     //
00955     aFallbackFontSummaryFileName = aFontDirName;
00956     aFallbackFontSummaryFileName.Append("/");
00957     aFallbackFontSummaryFileName.Append(PUBLIC_FONT_SUMMARY_NAME);
00958   }
00959 
00960   return PR_TRUE;
00961 }
00962 
00963 const char *
00964 nsFT2FontCatalog::GetFoundry(nsFontCatalogEntry *aFce)
00965 {
00966   nsCAutoString foundry(aFce->mVendorID);
00967   ToLowerCase(foundry);
00968   foundry.StripChars(" ");
00969   nsCStringKey key(foundry);
00970   const char *vendorName = (const char *)sVendorNames->Get(&key);
00971   if (!vendorName) {
00972     if (aFce->mVendorID[0])
00973       vendorName = aFce->mVendorID;
00974     else
00975       vendorName = "<unknown>";
00976   }
00977   return vendorName;
00978 }
00979 
00980 PRInt32
00981 nsFT2FontCatalog::GetNumEmbeddedBitmaps(nsFontCatalogEntry *aFce)
00982 {
00983   return aFce->mNumEmbeddedBitmaps;
00984 }
00985 
00986 PRBool
00987 nsFT2FontCatalog::HandleFontDir(FT_Library aFreeTypeLibrary, 
00988                                 nsFontCatalog *aFontCatalog,
00989                                 const nsACString &aFontSummariesDir, // native charset
00990                                 const nsACString &aFontDirName)      // native charset
00991 {
00992   int i, status = -1;
00993   PRBool rslt, current;
00994   nsCAutoString fileName;
00995   nsHashtable* fontFileNamesHash = nsnull;
00996   nsHashtable* fallbackFceHash = nsnull;
00997   nsresult rv;
00998   nsCAutoString fontSummaryFilename, fallbackFontSummaryFilename;
00999   nsFontCatalog *dirFontCatalog = nsnull;
01000   PRBool moreFilesInDir = PR_FALSE;
01001   nsCOMPtr<nsIFile> dir;
01002   nsCOMPtr<nsILocalFile> dirLocal;
01003   nsCOMPtr<nsILocalFile> dirEntry;
01004   nsCOMPtr<nsISimpleEnumerator> dirIterator;
01005   PRBool summary_needs_update = PR_FALSE;
01006   nsFontCatalogEntry *fce;
01007 
01008   //
01009   // temp holder for the font summaries in this dir
01010   //
01011   dirFontCatalog = NewFontCatalog();
01012   if (!dirFontCatalog)
01013     goto cleanup_and_return;
01014   // also hash to quick access
01015   fontFileNamesHash = new nsHashtable();
01016   if (!fontFileNamesHash)
01017     goto cleanup_and_return;
01018 
01019   //
01020   // Figure out where the font summary is
01021   //
01022   rslt = GetFontSummaryName(aFontDirName, aFontSummariesDir,
01023                                          fontSummaryFilename,
01024                                          fallbackFontSummaryFilename);
01025   if (!rslt) {
01026     FONT_CATALOG_PRINTF(("failed to get font summary name for %s %s",
01027                          PromiseFlatCString(aFontDirName).get(),
01028                          PromiseFlatCString(aFontSummariesDir).get()));
01029     goto cleanup_and_return;
01030   }
01031 
01032   FONT_CATALOG_PRINTF(("for \"%s\":\n    font summary = %s"
01033                                   "\n    fallback     = %s", 
01034                        PromiseFlatCString(aFontDirName).get(), 
01035                        PromiseFlatCString(fontSummaryFilename).get(),
01036                        fallbackFontSummaryFilename.Length()>0 ?
01037                        fallbackFontSummaryFilename.get()
01038                        :"<none>"));
01039             
01040   //
01041   // Get the font summaries
01042   //
01043   ReadFontDirSummary(fontSummaryFilename, fontFileNamesHash);
01044 
01045   //
01046   // Open the dir
01047   //
01048   dir = new nsLocalFile();
01049   dirLocal = do_QueryInterface(dir);
01050   dirLocal->InitWithNativePath(aFontDirName);
01051   rv = dir->GetDirectoryEntries(getter_AddRefs(dirIterator));
01052   if (NS_FAILED(rv)) {
01053     FONT_CATALOG_PRINTF(("failed to open dir (get iterator) for %s", 
01054                          PromiseFlatCString(aFontDirName).get()));
01055     goto cleanup_and_return;
01056   }
01057 
01058   rv = dirIterator->HasMoreElements(&moreFilesInDir);
01059   if (NS_FAILED(rv)) {
01060     FONT_CATALOG_PRINTF(("failed HasMoreElements"));
01061     goto cleanup_and_return;
01062   }
01063 
01064   //
01065   // Compare the files in the dir to the font summaries
01066   //
01067   while (moreFilesInDir) {
01068     PRBool isFile;
01069     current = PR_FALSE;
01070     rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry));
01071     if (NS_FAILED(rv)) {
01072       FONT_CATALOG_PRINTF(("failed GetNext"));
01073       goto cleanup_and_return;
01074     }
01075     //char *path;
01076     dirEntry->GetNativePath(fileName);
01077     FONT_CATALOG_PRINTF(("dirEntry = \"%s\"", fileName.get()));
01078     rv = dirEntry->IsFile(&isFile);
01079     if (NS_SUCCEEDED(rv) && isFile) {
01080       PRInt64 modtime;
01081       dirEntry->GetLastModifiedTime(&modtime);
01082       current = AddFceIfCurrent(fileName.get(), fontFileNamesHash,
01083                              modtime, dirFontCatalog);
01084       if (!current) {
01085         // Ignore the font summary itself
01086         if (fileName.Equals(fontSummaryFilename) ||
01087             fileName.Equals(fallbackFontSummaryFilename)) {
01088           FONT_CATALOG_PRINTF(("font summary %s is not a font", fileName.get()));
01089           current = PR_TRUE;
01090         }
01091         // If not in font summary, try the fallback summary
01092         else if (fallbackFontSummaryFilename.Length()) {
01093           if (!fallbackFceHash) {
01094             fallbackFceHash = new nsHashtable();
01095             if (fallbackFceHash) {
01096               ReadFontDirSummary(fallbackFontSummaryFilename, 
01097                                               fallbackFceHash);
01098             }
01099           }
01100           if (fallbackFceHash) {
01101             summary_needs_update = PR_TRUE;
01102             current = AddFceIfCurrent(fileName.get(), fallbackFceHash,
01103                               modtime, dirFontCatalog);
01104           }
01105         }
01106 
01107         //
01108         // If not found in font summary or fallback
01109         // then scan the font
01110         //
01111         if (!current) {
01112           summary_needs_update = PR_TRUE;
01113           HandleFontFile(aFreeTypeLibrary, dirFontCatalog,
01114                                       fileName.get());
01115         }
01116       }
01117     }
01118     rv = dirIterator->HasMoreElements(&moreFilesInDir);
01119     if (NS_FAILED(rv)) {
01120       FONT_CATALOG_PRINTF(("failed HasMoreElements"));
01121       goto cleanup_and_return;
01122     }
01123   }
01124 
01125   //
01126   // if hash count != 0 then needs update
01127   //
01128   if (fontFileNamesHash->Count()) {
01129     summary_needs_update = PR_TRUE;
01130   }
01131 
01132   //
01133   // Check if need to update font summary
01134   //
01135   if (summary_needs_update) {
01136     FONT_CATALOG_PRINTF(("update the font summary"));
01137     nsNameValuePairDB tmp_fc;
01138     if (!tmp_fc.OpenTmpForWrite(fontSummaryFilename))
01139       return 0; // failed to write but still got font data
01140     // print the Font Summary version
01141     PrintFontSummaryVersion(&tmp_fc);
01142     // print the font summaries
01143     PrintFontSummaries(&tmp_fc, dirFontCatalog);
01144     if (tmp_fc.HadError())
01145       return 0; // failed to write but still got font data
01146     tmp_fc.RenameTmp(PromiseFlatCString(fontSummaryFilename).get());
01147   }
01148 
01149   //
01150   // transfer the fce from this dir to the main font catalog
01151   //
01152   for (i=0; i<dirFontCatalog->numFonts; i++) {
01153     fce = dirFontCatalog->fonts[i];
01154     AddFont(aFontCatalog, fce);
01155   }
01156   dirFontCatalog->numFonts = 0;
01157 
01158   status = 0;
01159 
01160 cleanup_and_return:
01161   if(dirFontCatalog)
01162     FreeFontCatalog(dirFontCatalog);
01163   if(fontFileNamesHash) {
01164     fontFileNamesHash->Reset(FreeFceHashEntry, nsnull);
01165     delete fontFileNamesHash;
01166   }
01167   if(fallbackFceHash) {
01168     fallbackFceHash->Reset(FreeFceHashEntry, nsnull);
01169     delete fallbackFceHash;
01170   }
01171   return status;
01172 }
01173 
01174 void
01175 nsFT2FontCatalog::HandleFontFile(FT_Library aFreeTypeLibrary,
01176                                  nsFontCatalog *aFontCatalog,
01177                                  const char *aFontFileName)
01178 {
01179   int j, num_faces;
01180   nsFontCatalogEntry *fce;
01181 
01182   /* FONT_CATALOG_PRINTF(("handle font %s", aFontFileName)); */
01183   fce = NewFceFromFontFile(aFreeTypeLibrary, aFontFileName,
01184                                      0, &num_faces);
01185   if (!fce) {
01186     //FONT_CATALOG_PRINTF(("failed to catalog %s", aFontFileName));
01187     return;
01188   }
01189   AddFont(aFontCatalog, fce);
01190 
01191   /* loop thru the additional faces */
01192   for (j=1; j<num_faces; j++) {
01193     fce = NewFceFromFontFile(aFreeTypeLibrary, aFontFileName,
01194                                        j, nsnull);
01195     if (!fce) {
01196       //FONT_CATALOG_PRINTF(("failed to catalog %s/%d\n", aFontFileName, j));
01197       return;
01198     }
01199     AddFont(aFontCatalog, fce);
01200   }
01201 }
01202 
01203 PRBool
01204 nsFT2FontCatalog::InitGlobals(FT_Library lib)
01205 {
01206   nsDirCatalog *dirCatalog = nsnull;
01207   nsCAutoString prefix("font.directory.truetype.");
01208 #ifdef DEBUG
01209   int dump_catalog = 0;
01210   int num_ftfonts = 0;
01211   int i;
01212 #endif
01213   nsFontVendorName *vn = sVendorNamesList;
01214 
01215   nsulCodePageRangeLanguage *crl = nsnull;
01216 
01217   CallGetService(NS_PREF_CONTRACTID, &sPref);
01218   if (!sPref)
01219     goto cleanup_and_return;
01220 
01221   mFontCatalog = NewFontCatalog();
01222   if (!mFontCatalog)
01223     goto cleanup_and_return;
01224 
01225   sVendorNames = new nsHashtable();
01226   if (!sVendorNames)
01227     goto cleanup_and_return;
01228   while (vn->vendorID) {
01229     nsCAutoString name(vn->vendorID);
01230     ToLowerCase(name);
01231     nsCStringKey key(name);
01232     sVendorNames->Put(&key, (void*)vn->vendorName);
01233     vn++;
01234   }
01235 
01236   mRange1Language = new nsHashtable();
01237   if (!mRange1Language)
01238     goto cleanup_and_return;
01239   crl = ulCodePageRange1Language;
01240   while (crl->language) {
01241     nsCStringKey key(crl->language);
01242     mRange1Language->Put(&key, &(crl->bit));
01243     crl++;
01244   }
01245 
01246   mRange2Language = new nsHashtable();
01247   if (!mRange2Language)
01248     goto cleanup_and_return;
01249   crl = ulCodePageRange2Language;
01250   while (crl->language) {
01251     nsCStringKey key(crl->language);
01252     mRange2Language->Put(&key, &(crl->bit));
01253     crl++;
01254   }
01255 
01256   // get dirs list from prefs
01257   dirCatalog = NewDirCatalog();
01258   if (!dirCatalog)
01259     goto cleanup_and_return;
01260   sPref->EnumerateChildren(prefix.get(), GetDirsPrefEnumCallback,
01261                            dirCatalog);
01262 
01263   NS_TIMELINE_START_TIMER("nsFT2FontCatalog::GetFontCatalog");
01264   GetFontCatalog(lib, mFontCatalog, dirCatalog);
01265   NS_TIMELINE_STOP_TIMER("nsFT2FontCatalog::GetFontCatalog");
01266   NS_TIMELINE_MARK_TIMER("nsFT2FontCatalog::GetFontCatalog");
01267   FreeDirCatalog(dirCatalog);
01268 
01269   FixUpFontCatalog(mFontCatalog);
01270 #ifdef DEBUG
01271   if (dump_catalog)
01272     DumpFontCatalog(mFontCatalog);
01273 #endif
01274 
01275 #ifdef DEBUG
01276   for (i=0; i<mFontCatalog->numFonts; i++) {
01277     if (mFontCatalog->fonts[i]->mFlags&FCE_FLAGS_ISVALID)
01278       num_ftfonts++;
01279   }
01280   FONT_CATALOG_PRINTF(("can use %d TrueType fonts (font dirs hold %d files)",
01281               num_ftfonts, mFontCatalog->numFonts));
01282 #endif
01283 
01284   return(PR_TRUE);
01285 
01286 cleanup_and_return:
01287   FONT_CATALOG_PRINTF(("nsFT2FontCatalog::InitGlobals failed"));
01288   FreeGlobals();
01289   return(PR_FALSE);
01290 }
01291 
01292 //
01293 // Routine to tell if a char should be blank
01294 // This routing is simplistic but Erik van der Poel recommended
01295 // this and it seems to be sufficient for the windows code;
01296 // In the windows code see SHOULD_BE_SPACE_CHAR(ch)
01297 //
01298 PRBool
01299 nsFT2FontCatalog::IsSpace(FT_Long c)
01300 {
01301   switch (c) {
01302     case 0x0020: // ascii space
01303     case 0x00A0: // non-breaking space
01304     case 0x3000: // ideographic space
01305       return PR_TRUE;
01306   }
01307   // 2000 == EN quad
01308   // 2001 == EM quad
01309   // 2002 == EN space
01310   // 2003 == EM space
01311   // 2004 == 3 per EM space
01312   // 2005 == 4 per EM space
01313   // 2006 == 6 per EM space
01314   // 2007 == figure space
01315   // 2008 == punction space
01316   // 2009 == thin space
01317   // 200A == hair space
01318   // 200B == zero width space
01319 
01320   if ((c >= 0x2000) && (c <= 0x200b))
01321     return PR_TRUE;
01322   return PR_FALSE;
01323 }
01324 
01325 nsDirCatalog *
01326 nsFT2FontCatalog::NewDirCatalog()
01327 {
01328   nsDirCatalog *dc;
01329   dc = (nsDirCatalog *)calloc(1, sizeof(nsDirCatalog));
01330   return dc;
01331 }
01332 
01333 nsFontCatalogEntry *
01334 nsFT2FontCatalog::NewFceFromFontFile(FT_Library aFreeTypeLibrary,
01335                                      const char *aFontFileName,
01336                                      int aFaceIndex, int * aNumFaces)
01337 {
01338   PRUint32 i, len;
01339   nsFontCatalogEntry *fce;
01340   FT_Error fterror;
01341   FT_Face face = nsnull;
01342   FT_UInt glyph_index;
01343   FT_GlyphSlot slot;
01344   TT_OS2 *tt_os2;
01345   int error;
01346   struct stat file_info;
01347   int num_checked = 0;
01348   int blank_chars;
01349   nsCompressedCharMap ccmapObj;
01350   nsresult rv;
01351 
01352   fce = (nsFontCatalogEntry *)calloc(1, sizeof(nsFontCatalogEntry));
01353   if (!fce)
01354     return nsnull;
01355 
01356   FONT_SCAN_PRINTF(("font %s ", aFontFileName));
01357   if (aFaceIndex) {
01358     FONT_SCAN_PRINTF(("face %d ", aFaceIndex+1));
01359   }
01360 
01361   error = stat(aFontFileName, &file_info);
01362   if (error) {
01363     FONT_SCAN_PRINTF(("  unable to stat font file"));
01364     goto cleanup_and_return;
01365   }
01366 
01367   fce->mFontFileName = strdup(aFontFileName);
01368   if (!fce->mFontFileName)
01369     goto no_memory_cleanup_and_return;
01370 
01371   fce->mMTime = file_info.st_mtime;
01372   fce->mFaceIndex = aFaceIndex;
01373 
01374   // open the font
01375   rv = mFt2->NewFace(aFreeTypeLibrary, aFontFileName, aFaceIndex, &face);
01376   if (NS_FAILED(rv)) {
01377     FONT_SCAN_PRINTF(("  FreeType failed to open, error=%d", fterror));
01378     goto cleanup_and_return;
01379   }
01380   if (!FT_IS_SCALABLE(face)) {
01381     FONT_SCAN_PRINTF(("  not scalable, ignoring"));
01382     goto cleanup_and_return;
01383   }
01384 
01385   NS_ASSERTION(face->family_name,"font is missing FamilyName");
01386   if (!face->family_name)
01387     goto cleanup_and_return;
01388   nsTTFontFamilyEncoderInfo *ffei;
01389   ffei = nsFreeType2::GetCustomEncoderInfo(face->family_name);
01390   if (ffei) {
01391     fce->mFlags = FCE_FLAGS_ISVALID | FCE_FLAGS_SYMBOL;
01392   }
01393   else {
01394     for (i=0; i < face->num_charmaps; i++) {
01395 
01396       if (face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT) {
01397         if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS) {
01398           fce->mFlags = FCE_FLAGS_ISVALID | FCE_FLAGS_UNICODE;
01399           fterror = mFt2->SetCharmap(face, face->charmaps[i]);
01400           if (fterror) {
01401             FONT_SCAN_PRINTF(("failed to select unicode charmap"));
01402             goto cleanup_and_return;
01403           }
01404         }
01405 #if defined(TT_MS_ID_UCS_4)
01406           else if (face->charmaps[i]->encoding_id == TT_MS_ID_UCS_4) {
01407           fce->mFlags = FCE_FLAGS_ISVALID | FCE_FLAGS_UNICODE | FCE_FLAGS_SURROGATE;
01408           fterror = mFt2->SetCharmap(face, face->charmaps[i]);
01409           if (fterror) {
01410             FONT_SCAN_PRINTF(("failed to select unicode charmap"));
01411             goto cleanup_and_return;
01412           }
01413           break;
01414         }
01415 #endif
01416       }
01417     }
01418   }
01419   if (!fce->mFlags&FCE_FLAGS_ISVALID) {
01420     FONT_SCAN_PRINTF(("%s is missing cmap", face->family_name));
01421     goto cleanup_and_return;
01422   }
01423 
01424   mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2);
01425   if (!tt_os2) {
01426     FONT_SCAN_PRINTF(("unable to get OS2 table"));
01427     goto cleanup_and_return;
01428   }
01429   fce->mFontType = strdup("TrueType");
01430   if (!fce->mFontType)
01431     goto no_memory_cleanup_and_return;
01432   fce->mWeight = tt_os2->usWeightClass;
01433   fce->mWidth  = tt_os2->usWidthClass;
01434   fce->mCodePageRange1 = tt_os2->ulCodePageRange1;
01435   fce->mCodePageRange2 = tt_os2->ulCodePageRange2;
01436   // sadly too many fonts have vendor ID blank
01437   //NS_ASSERTION(*((char*)tt_os2->achVendID), "invalid vendor id");
01438   memset((char*)fce->mVendorID, 0, sizeof(fce->mVendorID));
01439   strncpy((char*)fce->mVendorID, (char*)tt_os2->achVendID, 
01440            sizeof(fce->mVendorID)-1);
01441   fce->mNumFaces = face->num_faces;
01442   if (aNumFaces!=nsnull)
01443     *aNumFaces = face->num_faces;
01444 
01445   //FONT_CATALOG_PRINTF(("family = %s", face->family_name));
01446   fce->mFamilyName = strdup(face->family_name);
01447   if (!fce->mFamilyName)
01448     goto no_memory_cleanup_and_return;
01449 
01450   fce->mStyleName = strdup(face->style_name);
01451   if (!fce->mStyleName)
01452     goto no_memory_cleanup_and_return;
01453 
01454   fce->mFaceFlags = face->face_flags;
01455   fce->mStyleFlags = face->style_flags;
01456   fce->mNumGlyphs = face->num_glyphs;
01457 
01458   fce->mNumEmbeddedBitmaps = face->num_fixed_sizes;
01459   if (fce->mNumEmbeddedBitmaps) {
01460     fce->mEmbeddedBitmapHeights = (int*)calloc(fce->mNumEmbeddedBitmaps,
01461                                       sizeof(fce->mEmbeddedBitmapHeights[0]));
01462     if (!fce->mEmbeddedBitmapHeights)
01463       goto no_memory_cleanup_and_return;
01464     for (int i=0; i<fce->mNumEmbeddedBitmaps; i++)
01465       fce->mEmbeddedBitmapHeights[i] = face->available_sizes[i].height;
01466   }
01467 
01468   if ((fce->mFlags & FCE_FLAGS_UNICODE) || (fce->mFlags & FCE_FLAGS_SURROGATE)) {
01469     if (fce->mFlags & FCE_FLAGS_SURROGATE) {
01470       ccmapObj.Extend();
01471     }
01472 
01473     // check fast methods are defined
01474     PRBool has_fast_methods;
01475     mFt2->SupportsExtFunc(&has_fast_methods);
01476 
01477     PRBool scan_done = PR_FALSE;
01478     if (has_fast_methods) {
01479       mFt2->GetFirstChar(face, &glyph_index, (FT_ULong*)&i);
01480       if (glyph_index == 0) {
01481         // no glyph in the font
01482         scan_done = PR_TRUE;
01483       }
01484     } else {
01485       i=0;
01486     }
01487 
01488     len = NUM_UNICODE_CHARS;
01489     if(fce->mFlags & FCE_FLAGS_SURROGATE) {
01490       len = 0xFFFFF;
01491     }
01492 
01493     blank_chars = 0;
01494     slot = face->glyph;
01495     FONT_SCAN_PRINTF(("            "));
01496 
01497     while (!scan_done && i < len) {
01498       if (!has_fast_methods) {
01499         mFt2->GetCharIndex(face, (FT_ULong)i, &glyph_index);
01500         //FONT_CATALOG_PRINTF(("i=%d, glyph_index=%d", i, glyph_index));
01501         if (glyph_index == 0) {
01502           goto next_char;
01503         }
01504       }
01505       if (gFontDebug & NS_FONT_DEBUG_FONT_SCAN) {
01506         if ((num_checked % 1000) == 0) {
01507           FONT_SCAN_PRINTF(("\b\b\b\b\b\b\b\b\b\b\b\b\b\b%7d glyphs", num_checked));
01508         }
01509       }
01510       num_checked++;
01511       rv = mFt2->LoadGlyph(face, glyph_index,
01512                  FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING);
01513       //FONT_CATALOG_PRINTF(("fterror = %d", fterror));
01514       if (NS_FAILED(rv)) {
01515         FONT_CATALOG_PRINTF(("error loading %d (glyph index = %d)", 
01516                     i, glyph_index));
01517         goto next_char;
01518       }
01519       if (slot->format == ft_glyph_format_outline) {
01520         //FONT_CATALOG_PRINTF(("n_contours=%d", slot->outline.n_contours));
01521         if ((slot->outline.n_contours==0) && (!IsSpace(i))) {
01522           blank_chars++;
01523           FT_Glyph glyph;
01524           FT_BBox bbox;
01525           mFt2->GetGlyph(slot, &glyph);
01526           mFt2->GlyphGetCBox(glyph, ft_glyph_bbox_pixels, &bbox);
01527           mFt2->DoneGlyph(glyph);
01528           if((bbox.xMax==0) && (bbox.xMin==0)
01529              && (bbox.yMax==0) && (bbox.yMin==0)) {
01530             goto next_char;
01531           }
01532           FONT_SCAN_PRINTF(("no contours %d (glyph index = %d)\n", i, 
01533                             glyph_index));
01534           FONT_CATALOG_PRINTF(("character 0x%04x no contour but glyph has "
01535                                "non-zero bounding box", i));
01536           NS_WARNING("character no contour but glyph has non-zero bounding box");
01537         }
01538       }
01539       else if (slot->format == ft_glyph_format_bitmap) {
01540         // this "empty bitmap" test is just a guess
01541         if ((slot->bitmap.rows==0) || (slot->bitmap.width==0)) {
01542           FONT_CATALOG_PRINTF(("no bitmap for glyph 0x%04x", i));
01543           FONT_CATALOG_PRINTF(("continue at line %d", __LINE__));
01544           FONT_SCAN_PRINTF(("empty bitmap %d (glyph index = %d)\n", 
01545                              i, glyph_index));
01546           goto next_char;
01547         }
01548       }
01549       else {
01550         NS_WARNING("need to test for empty (non-space char) glyph");
01551       }
01552       ccmapObj.SetChar(i);
01553       fce->mNumUsableGlyphs++;
01554 next_char:
01555       if (has_fast_methods) {
01556          FT_ULong ncharcode;
01557          mFt2->GetNextChar(face, (FT_ULong)i, &glyph_index, &ncharcode);
01558          i = ncharcode;
01559          if (glyph_index == 0) {
01560            // no more glyph in the font
01561            scan_done = PR_TRUE;
01562          }
01563       } else {
01564         i++;
01565       }
01566     }
01567     if (gFontDebug & NS_FONT_DEBUG_FONT_SCAN) {
01568       FONT_SCAN_PRINTF(("\b\b\b\b\b\b\b\b\b\b\b\b\b\b%7d glyphs", num_checked));
01569       if (blank_chars) {
01570         FONT_SCAN_PRINTF((" (%d invalid)", blank_chars));
01571       }
01572     }
01573     if (fce->mNumUsableGlyphs == 0)
01574       fce->mFlags |= FCE_FLAGS_ISVALID;
01575 
01576     fce->mCCMap = ccmapObj.NewCCMap();
01577   }
01578   else if (fce->mFlags & FCE_FLAGS_SYMBOL) {
01579     FONT_SCAN_PRINTF(("uses custom encoder"));
01580     if (ffei) {
01581       nsCOMPtr<nsICharRepresentable> mapper;
01582       mapper = do_QueryInterface(ffei->mEncodingInfo->mConverter);
01583       if (mapper) {
01584         fce->mCCMap = MapperToCCMap(mapper);
01585       }
01586     }
01587   }
01588   else {
01589     FONT_SCAN_PRINTF(("unknown font encoding"));
01590   }
01591   if (!fce->mCCMap) {
01592     FONT_CATALOG_PRINTF(("Failed to copy CCMap"));
01593     goto cleanup_and_return;
01594   }
01595 
01596   mFt2->DoneFace(face);
01597 
01598   FONT_SCAN_PRINTF(("\n"));
01599   return fce;
01600 
01601 // regardless of why we could not use the file we want to put it in the
01602 // catalog so we do not reopen invalid files every time we startup
01603 cleanup_and_return:
01604   FONT_CATALOG_PRINTF(("nsFT2FontCatalog::NewFceFromFontFile failed"));
01605   fce->mFlags &= ~FCE_FLAGS_ISVALID;
01606   fce->mFontType = strdup("");
01607   fce->mNumFaces = 0;
01608   if (aNumFaces)
01609     *aNumFaces = 0;
01610   fce->mFamilyName = strdup("");
01611   fce->mFlags = 0;
01612   fce->mStyleName = strdup("");
01613   FREE_IF(fce->mEmbeddedBitmapHeights);
01614   if (face)
01615     mFt2->DoneFace(face);
01616   FONT_SCAN_PRINTF(("\n"));
01617   return fce;
01618 
01619 no_memory_cleanup_and_return:
01620   FONT_CATALOG_PRINTF(("nsFT2FontCatalog::NewFceFromFontFile: out of memory"));
01621   FREE_IF(fce->mFontFileName);
01622   FREE_IF(fce->mFontType);
01623   FREE_IF(fce->mFamilyName);
01624   FREE_IF(fce->mStyleName);
01625   if (fce->mCCMap)
01626     FreeCCMap(fce->mCCMap);
01627   FREE_IF(fce);
01628   if (face)
01629     mFt2->DoneFace(face);
01630   FONT_SCAN_PRINTF(("\n"));
01631   return nsnull;
01632 }
01633 
01634 nsFontCatalogEntry *
01635 nsFT2FontCatalog::NewFceFromSummary(nsNameValuePairDB *aDB)
01636 {
01637   const char *type, *name, *value;
01638   PRBool rslt;
01639   nsFontCatalogEntry *fce = nsnull;
01640   long longVal;
01641   unsigned long uLongVal;
01642   int num, intVal, i;
01643   nsCompressedCharMap ccmapObj;
01644 
01645   fce = (nsFontCatalogEntry *)calloc(1, sizeof(nsFontCatalogEntry));
01646   if (!fce)
01647     goto cleanup_and_return;
01648 
01649   if (!aDB->GetNextGroup(&type, "Font_", 5)) {
01650     FONT_CATALOG_PRINTF(("file garbled: expected begin=Font_, got %s", type));
01651     goto cleanup_and_return;
01652   }
01653 
01654   while (aDB->GetNextElement(&name, &value) > 0) {
01655     if (STRMATCH(name,"FamilyName")) {
01656       if (fce->mFamilyName) {
01657         FONT_CATALOG_PRINTF(("family name defined multiple times (%s, %s)", 
01658                           fce->mFamilyName, value));
01659         goto cleanup_and_return;
01660       }
01661       fce->mFamilyName = strdup(value);
01662       if (!fce->mFamilyName)
01663         goto cleanup_and_return;
01664     }
01665     else if (STRMATCH(name,"Flags")) {
01666       if (fce->mFlags != 0) {
01667         FONT_CATALOG_PRINTF(("Flags defined multiple times (%s)",
01668                 fce->mFontFileName?fce->mFontFileName:""));
01669         goto cleanup_and_return;
01670       }
01671       num = sscanf(value, "%lx", &uLongVal);
01672       if (num != 1) {
01673         FONT_CATALOG_PRINTF(("failed to parse Flags (%s)",value));
01674         goto cleanup_and_return;
01675       }
01676       fce->mFlags = uLongVal;
01677       if (fce->mFlags & FCE_FLAGS_SURROGATE) {
01678         ccmapObj.Extend();
01679       }
01680     }
01681     else if (STRMATCH(name,"FontFileName")) {
01682       if (fce->mFontFileName) {
01683         FONT_CATALOG_PRINTF(("font filename defined multiple times (%s, %s)",
01684                           fce->mFontFileName, value));
01685         goto cleanup_and_return;
01686       }
01687       fce->mFontFileName = strdup(value);
01688       if (!fce->mFontFileName)
01689         goto cleanup_and_return;
01690     }
01691     else if (STRMATCH(name,"MTime")) {
01692       if (fce->mMTime != 0) {
01693         FONT_CATALOG_PRINTF(("time defined multiple times (%s)",
01694                 fce->mFontFileName?fce->mFontFileName:""));
01695         goto cleanup_and_return;
01696       }
01697       num = sscanf(value, "%lu", &uLongVal);
01698       if ((num != 1) || (uLongVal==0)) {
01699         FONT_CATALOG_PRINTF(("failed to parse time (%s)",value));
01700         goto cleanup_and_return;
01701       }
01702       fce->mMTime = uLongVal;
01703     }
01704     else if (STRMATCH(name,"FontType")) {
01705       if (fce->mFontType) {
01706         FONT_CATALOG_PRINTF(("font type defined multiple times (%s, %s)",
01707                           fce->mFontType, value));
01708         goto cleanup_and_return;
01709       }
01710       fce->mFontType = strdup(value);
01711       if (!fce->mFontType)
01712         goto cleanup_and_return;
01713     }
01714     else if (STRMATCH(name,"FaceIndex")) {
01715       if (fce->mFaceIndex != 0) {
01716         FONT_CATALOG_PRINTF(("face index defined multiple times (%d, %s)",
01717                           fce->mFaceIndex, value));
01718         goto cleanup_and_return;
01719       }
01720       longVal = atol(value);
01721       if (longVal<0) {
01722         FONT_CATALOG_PRINTF(("failed to parse face index (%s)",value));
01723         goto cleanup_and_return;
01724       }
01725       fce->mFaceIndex = longVal;
01726     }
01727     else if (STRMATCH(name,"NumFaces")) {
01728       if (fce->mNumFaces != 0) {
01729         FONT_CATALOG_PRINTF(("num faces defined multiple times (%d, %s)",
01730                           fce->mNumFaces, value));
01731         goto cleanup_and_return;
01732       }
01733       intVal = atoi(value);
01734       if (intVal<0) {
01735         FONT_CATALOG_PRINTF(("failed to parse num faces (%s)",value));
01736         goto cleanup_and_return;
01737       }
01738       fce->mNumFaces = intVal;
01739     }
01740     else if (STRMATCH(name,"StyleName")) {
01741       if (fce->mStyleName != 0) {
01742         FONT_CATALOG_PRINTF(("font style defined multiple times (%s, %s)", 
01743                               fce->mStyleName, value));
01744         goto cleanup_and_return;
01745       }
01746       fce->mStyleName = strdup(value);
01747       if (!fce->mStyleName)
01748         goto cleanup_and_return;
01749     }
01750     else if (STRMATCH(name,"NumGlyphs")) {
01751       if (fce->mNumGlyphs != 0) {
01752         FONT_CATALOG_PRINTF(("num glyphs defined multiple times (%d, %s)",
01753                                      fce->mNumGlyphs, value));
01754         goto cleanup_and_return;
01755       }
01756       intVal = atoi(value);
01757       if (intVal<0) {
01758         FONT_CATALOG_PRINTF(("failed to parse num glyphs (%s)",value));
01759         goto cleanup_and_return;
01760       }
01761       fce->mNumGlyphs = intVal;
01762     }
01763     else if (STRMATCH(name,"NumUsableGlyphs")) {
01764       if (fce->mNumUsableGlyphs != 0) {
01765         FONT_CATALOG_PRINTF(("num usable glyphs defined multiple times (%d, %s)",
01766                                      fce->mNumUsableGlyphs, value));
01767         goto cleanup_and_return;
01768       }
01769       intVal = atoi(value);
01770       if (intVal<0) {
01771         FONT_CATALOG_PRINTF(("failed to parse num usable glyphs (%s)",value));
01772         goto cleanup_and_return;
01773       }
01774       fce->mNumUsableGlyphs = intVal;
01775     }
01776     else if (STRMATCH(name,"FaceFlags")) {
01777       if (fce->mFaceFlags != 0) {
01778         FONT_CATALOG_PRINTF(("face flags defined multiple times (0x%lx, %s)",
01779                           fce->mFaceFlags, value));
01780         goto cleanup_and_return;
01781       }
01782       num = sscanf(value, "%lx", &uLongVal);
01783       if (num != 1) {
01784         FONT_CATALOG_PRINTF(("failed to parse face flags (%s)",value));
01785         goto cleanup_and_return;
01786       }
01787       fce->mFaceFlags = uLongVal;
01788     }
01789     else if (STRMATCH(name,"StyleFlags")) {
01790       if (fce->mStyleFlags != 0) {
01791         FONT_CATALOG_PRINTF(("style flags defined multiple times (0x%lx, %s)",
01792                           fce->mStyleFlags, value));
01793         goto cleanup_and_return;
01794       }
01795       num = sscanf(value, "%lx", &uLongVal);
01796       if (num != 1) {
01797         FONT_CATALOG_PRINTF(("failed to parse style flags (%s)",value));
01798         goto cleanup_and_return;
01799       }
01800       fce->mStyleFlags = uLongVal;
01801     }
01802     else if (STRMATCH(name,"Weight")) {
01803       if (fce->mWeight != 0) {
01804         FONT_CATALOG_PRINTF(("weight defined multiple times (0x%d, %s)",
01805                           fce->mWeight, value));
01806         goto cleanup_and_return;
01807       }
01808       intVal = atoi(value);
01809       if ((intVal<0) || (intVal>950)) {
01810         FONT_CATALOG_PRINTF(("failed to parse weight (%s)",value));
01811         goto cleanup_and_return;
01812       }
01813       fce->mWeight = (unsigned short)intVal;
01814     }
01815     else if (STRMATCH(name,"Width")) {
01816       if (fce->mWidth != 0) {
01817         FONT_CATALOG_PRINTF(("width defined multiple times (0x%d, %s)",
01818                           fce->mWeight, value));
01819         goto cleanup_and_return;
01820       }
01821       intVal = atoi(value);
01822       if ((intVal<0) || (intVal>9)) {
01823         FONT_CATALOG_PRINTF(("failed to parse (or invalid) width (%s)",value));
01824         goto cleanup_and_return;
01825       }
01826       fce->mWidth = (unsigned short)intVal;
01827     }
01828     else if (STRMATCH(name,"CodePageRange1")) {
01829       if (fce->mCodePageRange1 != 0) {
01830         FONT_CATALOG_PRINTF(("CodePageRange1 defined multiple times (0x%lx, %s)",
01831                           fce->mCodePageRange1, value));
01832         goto cleanup_and_return;
01833       }
01834       num = sscanf(value, "%lx", &uLongVal);
01835       if (num != 1) {
01836         FONT_CATALOG_PRINTF(("failed to parse mCodePageRange1 (%s)",value));
01837         goto cleanup_and_return;
01838       }
01839       fce->mCodePageRange1 = uLongVal;
01840     }
01841     else if (STRMATCH(name,"CodePageRange2")) {
01842       if (fce->mCodePageRange2 != 0) {
01843         FONT_CATALOG_PRINTF(("CodePageRange2 defined multiple times (0x%lx, %s)",
01844                           fce->mCodePageRange2, value));
01845         goto cleanup_and_return;
01846       }
01847       num = sscanf(value, "%lx", &uLongVal);
01848       if (num != 1) {
01849         FONT_CATALOG_PRINTF(("failed to parse mCodePageRange2 (%s)",value));
01850         goto cleanup_and_return;
01851       }
01852       fce->mCodePageRange2 = uLongVal;
01853     }
01854     else if (STRMATCH(name,"VendorID")) {
01855       if (fce->mVendorID[0] != '\0') {
01856         FONT_CATALOG_PRINTF(("vendor id defined multiple times (%s, %s)",
01857                           fce->mVendorID, value));
01858         goto cleanup_and_return;
01859       }
01860       memset((char*)fce->mVendorID, 0, sizeof(fce->mVendorID));
01861       strncpy((char*)fce->mVendorID, value, sizeof(fce->mVendorID)-1);
01862     }
01863     else if (STRMATCH(name,"EmbeddedBitmapHeights")) {
01864       if (fce->mNumEmbeddedBitmaps != 0) {
01865         FONT_CATALOG_PRINTF(("EmbeddedBitmapHeights defined multiple times"));
01866         goto cleanup_and_return;
01867       }
01868       int embeddedBitmapHeights[1024];
01869       int maxEmbeddedBitmaps =
01870               sizeof(embeddedBitmapHeights)/sizeof(embeddedBitmapHeights[0]);
01871       int numEmbeddedBitmaps = 0;
01872       const char *p = value;
01873       const char *q;
01874       while ((q=strchr(p, ','))) {
01875         intVal = atoi(p);
01876         if (intVal < 1) {
01877           FONT_CATALOG_PRINTF(("failed to parse EmbeddedBitmapHeights(%s)",value));
01878           goto cleanup_and_return;
01879         }
01880         embeddedBitmapHeights[numEmbeddedBitmaps++] = intVal;
01881         if (numEmbeddedBitmaps >= maxEmbeddedBitmaps) {
01882           FONT_CATALOG_PRINTF(("can only handle %d numEmbeddedBitmaps",
01883                                 maxEmbeddedBitmaps));
01884           break;
01885         }
01886         p = q + 1; // point to next height
01887       }
01888       fce->mNumEmbeddedBitmaps = numEmbeddedBitmaps;
01889       if (fce->mNumEmbeddedBitmaps) {
01890         fce->mEmbeddedBitmapHeights = (int*)calloc(fce->mNumEmbeddedBitmaps,
01891                                                     sizeof(int));
01892         if (!fce->mEmbeddedBitmapHeights)
01893           goto cleanup_and_return;
01894         for (int i=0; i<fce->mNumEmbeddedBitmaps; i++)
01895           fce->mEmbeddedBitmapHeights[i] = embeddedBitmapHeights[i];
01896       }
01897     }
01898     else if (STRNMATCH(name,"CCMap:",6)) {
01899       num = sscanf(name+6, "%lx", &uLongVal);
01900       if (num != 1) {
01901         FONT_CATALOG_PRINTF(("failed to parse CCMap address (%s)",name+6));
01902         goto cleanup_and_return;
01903       }
01904       rslt = ParseCCMapLine(&ccmapObj, uLongVal, value);
01905       if (!rslt) {
01906         FONT_CATALOG_PRINTF(("failed to parse CCMap value (%s)",value));
01907         goto cleanup_and_return;
01908       }
01909     }
01910   }
01911 
01912   fce->mCCMap = ccmapObj.NewCCMap();
01913 
01914   if (!fce->mCCMap) {
01915     FONT_CATALOG_PRINTF(("missing char map"));
01916     goto cleanup_and_return;
01917   }
01918   if (!fce->mFamilyName) {
01919     FONT_CATALOG_PRINTF(("missing family name"));
01920     goto cleanup_and_return;
01921   }
01922   if ((fce->mFlags&FCE_FLAGS_ISVALID) && (fce->mFlags == 0)) {
01923     FONT_CATALOG_PRINTF(("missing flags"));
01924     goto cleanup_and_return;
01925   }
01926   if (!fce->mFontFileName) {
01927     FONT_CATALOG_PRINTF(("missing font file name"));
01928     goto cleanup_and_return;
01929   }
01930   if (fce->mMTime == 0) {
01931     FONT_CATALOG_PRINTF(("missing mtime"));
01932     goto cleanup_and_return;
01933   }
01934   if (!fce->mFontType) {
01935     FONT_CATALOG_PRINTF(("missing font type"));
01936     goto cleanup_and_return;
01937   }
01938   if (!fce->mStyleName) {
01939     FONT_CATALOG_PRINTF(("missing style name"));
01940     goto cleanup_and_return;
01941   }
01942   if ((fce->mFlags&FCE_FLAGS_ISVALID) && (fce->mNumGlyphs == 0)) {
01943     FONT_CATALOG_PRINTF(("missing num glyphs"));
01944     goto cleanup_and_return;
01945   }
01946   if (fce->mFlags&FCE_FLAGS_ISVALID 
01947       && ((fce->mFlags & FCE_FLAGS_UNICODE) || (fce->mFlags & FCE_FLAGS_SURROGATE))
01948       && (fce->mNumUsableGlyphs == 0)) {
01949     FONT_CATALOG_PRINTF(("missing num usable glyphs"));
01950     goto cleanup_and_return;
01951   }
01952 
01953   return fce;
01954 
01955 cleanup_and_return:
01956   FONT_CATALOG_PRINTF(("nsFT2FontCatalog::NewFceFromSummary failed"));
01957   if (fce->mCCMap)
01958     FreeCCMap(fce->mCCMap);
01959   FREE_IF(fce->mFamilyName);
01960   FREE_IF(fce->mFontFileName);
01961   FREE_IF(fce->mFontType);
01962   FREE_IF(fce->mStyleName);
01963   FREE_IF(fce->mEmbeddedBitmapHeights);
01964   FREE_IF(fce);
01965   return nsnull;
01966 }
01967 
01968 nsFontCatalog *
01969 nsFT2FontCatalog::NewFontCatalog()
01970 {
01971   nsFontCatalog *fc;
01972   fc = (nsFontCatalog *)calloc(1, sizeof(nsFontCatalog));
01973   return fc;
01974 }
01975 
01976 PRBool
01977 nsFT2FontCatalog::ParseCCMapLine(nsCompressedCharMap *aCCMapObj, long base, 
01978                                  const char *valString)
01979 {
01980   int i, j, len;
01981   unsigned int byte;
01982   PRUint32 pagechar = (PRUint32)base;
01983 
01984   // check we have the right number of chars
01985   len = strlen(valString);
01986   if (len != (2*(CCMAP_BITS_PER_PAGE/8)))
01987     return PR_FALSE;
01988 
01989   const char *p = valString;
01990   for (i=0; i<(CCMAP_BITS_PER_PAGE/8); i++) {
01991 #if 0 // scanf is way too slow
01992     int num = sscanf(valString+(2*i), "%2x", &byte);
01993     if (num != 1)
01994       return PR_FALSE;
01995 #else
01996     NS_ASSERTION((*p>='0' && *p<='9')
01997               || (*p>='a' && *p<='f')
01998               || (*p>='A' && *p<='F'), "Invalid ccmap char");
01999     if (*p <= '9')
02000       byte = *p++ - '0';
02001     else {
02002       byte = (*p++ & 0x4F) - 'A' + 10;
02003     }
02004     byte <<= 4;
02005     NS_ASSERTION((*p>='0' && *p<='9')
02006               || (*p>='a' && *p<='f')
02007               || (*p>='A' && *p<='F'), "Invalid ccmap char");
02008     if (*p <= '9')
02009       byte |= *p++ - '0';
02010     else {
02011       byte |= (*p++ & 0x4F) - 'A' + 10;
02012     }
02013 #endif
02014     if (byte == 0) {
02015       pagechar += 8;
02016       continue;
02017     }
02018 
02019     for (j=0; j<8; j++) {
02020       if (byte & (1<<j))
02021         aCCMapObj->SetChar(pagechar);
02022       pagechar++;
02023     }
02024   }
02025   return PR_TRUE;
02026 }
02027 
02028 
02029 void
02030 nsFT2FontCatalog::PrintCCMap(nsNameValuePairDB *aDB, PRUint16 *aCCMap)
02031 {
02032   if (!aCCMap)
02033     return;
02034 
02035   PRUint32 page = CCMAP_BEGIN_AT_START_OF_MAP;
02036   while (NextNonEmptyCCMapPage(aCCMap, &page)) {
02037     //FONT_CATALOG_PRINTF(("page starting at 0x%04x has chars", page));
02038     PrintPageBits(aDB, aCCMap, page);
02039   }
02040 }
02041 
02042 void
02043 nsFT2FontCatalog::PrintFontSummaries(nsNameValuePairDB *aDB, 
02044                                      nsFontCatalog *aFontCatalog)
02045 {
02046   int i;
02047   nsFontCatalogEntry *fce;
02048   char font_num[30];
02049   char buf[30];
02050 
02051   aDB->PutStartGroup("FontSummariesInfo");
02052   aDB->PutElement("", "#############################");
02053   aDB->PutElement("", "# Font Summaries            #");
02054   aDB->PutElement("", "#############################");
02055   aDB->PutElement("", "#");
02056   sprintf(buf, "%d", aFontCatalog->numFonts);
02057   aDB->PutElement("NumFonts", buf);
02058   aDB->PutEndGroup("FontSummariesInfo");
02059   for (i=0; i<aFontCatalog->numFonts; i++) {
02060     fce = aFontCatalog->fonts[i];
02061     sprintf(font_num, "Font_%d", i);
02062     aDB->PutStartGroup(font_num);
02063     aDB->PutElement("FamilyName",     fce->mFamilyName);
02064     sprintf(buf, "%08x",             fce->mFlags);
02065     aDB->PutElement("Flags", buf);
02066     aDB->PutElement("FontFileName",   fce->mFontFileName);
02067     sprintf(buf, "%ld",               fce->mMTime);
02068     aDB->PutElement("MTime", buf);
02069     aDB->PutElement("FontType",       fce->mFontType);
02070     sprintf(buf, "%d",                fce->mFaceIndex);
02071     aDB->PutElement("FaceIndex", buf);
02072     sprintf(buf, "%d",                fce->mNumFaces);
02073     aDB->PutElement("NumFaces", buf);
02074     aDB->PutElement("StyleName",      fce->mStyleName);
02075     sprintf(buf, "%d",                fce->mNumGlyphs);
02076     aDB->PutElement("NumGlyphs", buf);
02077     sprintf(buf, "%d",                fce->mNumUsableGlyphs);
02078     aDB->PutElement("NumUsableGlyphs", buf);
02079     sprintf(buf, "%08lx",             fce->mFaceFlags);
02080     aDB->PutElement("FaceFlags", buf);
02081     sprintf(buf, "%08lx",             fce->mStyleFlags);
02082     aDB->PutElement("StyleFlags", buf);
02083     sprintf(buf, "%d",                fce->mWeight);
02084     aDB->PutElement("Weight", buf);
02085     sprintf(buf, "%d",                fce->mWidth);
02086     aDB->PutElement("Width", buf);
02087     sprintf(buf, "%08lx",             fce->mCodePageRange1);
02088     aDB->PutElement("CodePageRange1", buf);
02089     sprintf(buf, "%08lx",             fce->mCodePageRange2);
02090     aDB->PutElement("CodePageRange2", buf);
02091     aDB->PutElement("VendorID",       fce->mVendorID);
02092     nsCAutoString embeddedHeightStr("");
02093     for (int j=0; j<fce->mNumEmbeddedBitmaps; j++) {
02094       sprintf(buf, "%d,", fce->mEmbeddedBitmapHeights[j]);
02095       embeddedHeightStr.Append(buf);
02096     }
02097     aDB->PutElement("EmbeddedBitmapHeights", 
02098                PromiseFlatCString(embeddedHeightStr).get());
02099     aDB->PutElement("", "# ccmap");
02100 
02101     PrintCCMap(aDB, fce->mCCMap);
02102     aDB->PutEndGroup(font_num);
02103   }
02104 }
02105 
02106 void
02107 nsFT2FontCatalog::PrintFontSummaryVersion(nsNameValuePairDB *aDB)
02108 {
02109   char buf[30];
02110 
02111   aDB->PutStartGroup(FONT_SUMMARY_VERSION_TAG);
02112   aDB->PutElement("", "#############################");
02113   aDB->PutElement("", "# Font Summary Version      #");
02114   aDB->PutElement("", "#############################");
02115   aDB->PutElement("", "#");
02116   sprintf(buf, "%u.%u.%u", FONT_SUMMARY_VERSION_MAJOR, 
02117                            FONT_SUMMARY_VERSION_MINOR,
02118                            FONT_SUMMARY_VERSION_REV);
02119   aDB->PutElement("Version", buf);
02120   aDB->PutEndGroup(FONT_SUMMARY_VERSION_TAG);
02121 }
02122 
02123 void
02124 nsFT2FontCatalog::PrintPageBits(nsNameValuePairDB *aDB, PRUint16 *aCCMap, 
02125                                 PRUint32 aPageStart)
02126 {
02127   int i;
02128   PRUint32 pagechar = aPageStart;
02129   char addr[64];
02130   char buf[64];
02131 
02132 
02133   nsCAutoString ccmap_line("");
02134   for (i=0; i<(CCMAP_BITS_PER_PAGE/8); i++) {
02135     unsigned char val = 0;
02136     for (int j=0; j<8; j++) {
02137       if (CCMAP_HAS_CHAR_EXT(aCCMap, pagechar)) {
02138         val |= 1 << j;
02139       }
02140       pagechar++;
02141     }
02142     sprintf(buf, "%02x", val);
02143     ccmap_line.Append(buf);
02144   }
02145   sprintf(addr, "CCMap:0x%04lx", (long)aPageStart);
02146   aDB->PutElement(addr, PromiseFlatCString(ccmap_line).get());
02147 }
02148 
02149 PRBool
02150 nsFT2FontCatalog::ReadFontDirSummary(const nsACString& aFontSummaryFilename,
02151                                      nsHashtable* aFontFileNamesHash)
02152 {
02153   nsNameValuePairDB fc;
02154   int status;
02155 
02156   if (!fc.OpenForRead(aFontSummaryFilename)) {
02157     FONT_CATALOG_PRINTF(("could not open font catalog %s", 
02158                          PromiseFlatCString(aFontSummaryFilename).get()));
02159     return PR_FALSE;
02160   }
02161 
02162   //
02163   // check the font summary version number
02164   //
02165   status = CheckFontSummaryVersion(&fc);
02166   if (status != FC_FILE_OKAY)
02167     goto cleanup_and_return;
02168 
02169   //
02170   // read font summaries
02171   //
02172   ReadFontSummaries(aFontFileNamesHash, &fc);
02173 
02174   return PR_TRUE;
02175 
02176 cleanup_and_return:
02177   FONT_CATALOG_PRINTF(("nsFT2FontCatalog::ReadFontDirSummary failed"));
02178   return PR_FALSE;
02179 }
02180 
02181 int
02182 nsFT2FontCatalog::ReadFontSummaries(nsHashtable* aFontHash, 
02183                                     nsNameValuePairDB *aDB)
02184 {
02185 
02186   const char *type, *name, *value;
02187   int i, numFonts = 0;
02188   nsFontCatalogEntry *fce = nsnull;
02189 
02190   //
02191   // Get the number of font summaries
02192   //
02193   if (!aDB->GetNextGroup(&type, "FontSummariesInfo")) {
02194     FONT_CATALOG_PRINTF(("file garbled: expected begin=FontSummariesInfo, "
02195                          "got %s", type));
02196     goto cleanup_and_return;
02197   }
02198   while (aDB->GetNextElement(&name, &value) > 0) {
02199     if (strcmp(name, "NumFonts")==0) {
02200       numFonts = atoi(value);
02201       if (numFonts<0) {
02202         FONT_CATALOG_PRINTF(("failed to parse num fonts (%s)", value));
02203         goto cleanup_and_return;
02204       }
02205     }
02206   }
02207 
02208   for (i=0; i<numFonts; i++) {
02209     fce = NewFceFromSummary(aDB);
02210     if (!fce)
02211       goto cleanup_and_return;
02212     nsCStringKey key(fce->mFontFileName);
02213     // Since we are hashing by file name we need to add a FaceIndex
02214     // else we would lose the other ttc faces
02215     if (fce->mFaceIndex != 0) {
02216       // add face num to hash key
02217       nsCAutoString key_str(fce->mFontFileName);
02218       char buf[20];
02219       sprintf(buf, "/%d", fce->mFaceIndex);
02220       key_str.Append(buf);
02221       key = key_str;
02222     }
02223     FONT_CATALOG_PRINTF(("key = %s", key.GetString()));
02224     aFontHash->Put(&key, (void *)fce);
02225   }
02226 
02227   return numFonts;
02228 
02229 cleanup_and_return:
02230   FONT_CATALOG_PRINTF(("nsFT2FontCatalog::ReadFontSummaries failed"));
02231   return 0;
02232 }
02233 
02234 unsigned long
02235 nsFT2FontCatalog::GetRangeLanguage(const nsACString & aLanguage,
02236                                    PRInt16 aRange)
02237 {
02238   unsigned long *bit;
02239   if (aLanguage.IsEmpty())
02240     return 0;
02241   nsCStringKey key(aLanguage);
02242   if (aRange == CPR1)
02243     bit = (unsigned long *)(mRange1Language->Get(&key));
02244   if (aRange == CPR2)
02245     bit = (unsigned long *)(mRange2Language->Get(&key));
02246   if (bit)
02247     return *bit;
02248   return 0;
02249 }
02250 
02251 nsFontVendorName sVendorNamesList[] = {
02252   { "2REB", "2Rebels"                                     },
02253   { "39BC", "Finley's Barcode Fonts"                      },
02254   { "3ip",  "Three Islands Press"                         },
02255   { "918",  "RavenType"                                   },
02256   { "ABC",  "Altek Instruments"                           },
02257   { "ACUT", "Acute Type"                                  },
02258   { "ADBE", "Adobe"                                       },
02259   { "AGFA", "Agfa Monotype"                               },
02260   { "ALPH", "Alphameric Broadcast Solutions"              },
02261   { "ALTS", "Altsys (Macromedia)"                         },
02262   { "AOP",  "An Art of Penguin"                           },
02263   { "APOS", "Apostrophic Laboratories"                    },
02264   { "APPL", "Apple"                                       },
02265   { "ARPH", "Arphic Technology"                           },
02266   { "ARS",  "EN ARS"                                      },
02267   { "ATEC", "Page Technology Marketing"                   },
02268   { "AZLS", "Azalea Software"                             },
02269   { "B&H",  "Bigelow & Holmes"                            },
02270   { "BARS", "CIA (BAR CODES) UK"                          },
02271   { "BERT", "Berthold"                                    },
02272   { "BITM", "Bitmap Software"                             },
02273   { "BITS", "Bitstream"                                   },
02274   { "BLAH", "Mister Bla's Fontworx"                       },
02275   { "BORW", "Borware"                                     },
02276   { "BOYB", "BoyBeaver Fonts"                             },
02277   { "BRTC", "Bear Rock Technologies"                      },
02278   { "BWFW", "B/W Fontworks"                               },
02279   { "C21",  "Club 21"                                     },
02280   { "CAK",  "pluginfonts"                                 },
02281   { "CANO", "Canon"                                       },
02282   { "CASL", "H.W. Caslon"                                 },
02283   { "CDAC", "Centre for Development of Advanced Computing"},
02284   { "CFA",  "Computer Fonts Australia"                    },
02285   { "CONR", "Connare"                                     },
02286   { "COOL", "Cool Fonts"                                  },
02287   { "CORD", "corduroy"                                    },
02288   { "CTDL", "China Type Designs"                          },
02289   { "cwwf", "Computers World Wide/AC Capital Funding"     },
02290   { "DAMA", "Dalton Maag"                                 },
02291   { "DELV", "Delve Media Arts"                            },
02292   { "DFS",  "Datascan Font Service"                       },
02293   { "DGL",  "Digital Graphic Labs foundry"                },
02294   { "DS",   "Dainippon Screen"                            },
02295   { "DSCI", "Design Science"                              },
02296   { "DSST", "Dubina Nikolay"                              },
02297   { "DTC",  "Digital Typeface"                            },
02298   { "DTPS", "DTP-Software"                                },
02299   { "dtpT", "dtpTypes"                                    },
02300   { "DUXB", "Duxbury Systems"                             },
02301   { "DYNA", "DynaLab"                                     },
02302   { "EDGE", "Rivers Edge"                                 },
02303   { "EFF",  "Electronic Font Foundry"                     },
02304   { "EFNT", "E Fonts L.L.C."                              },
02305   { "ELSE", "Elseware (Hewlett-Packard)"                  },
02306   { "EMGR", "Emigre"                                      },
02307   { "EPSN", "Epson"                                       },
02308   { "ESIG", "E-Signature"                                 },
02309   { "EVER", "Everson Typography"                          },
02310   { "FBI",  "The Font Bureau"                             },
02311   { "FCAB", "The Font Cabinet"                            },
02312   { "FCAN", "fontage canada"                              },
02313   { "FNTF", "Fontfoundry"                                 },
02314   { "FONT", "Font Source"                                 },
02315   { "FS",   "Formula Solutions"                           },
02316   { "FSE",  "Font Source Europe"                          },
02317   { "FSI",  "FSI Fonts und Software"                      },
02318   { "FTFT", "FontFont"                                    },
02319   { "FWRE", "Fontware"                                    },
02320   { "GALA", "Galápagos Design Group"                      },
02321   { "GD",   "GD Fonts"                                    },
02322   { "GF",   "GarageFonts"                                 },
02323   { "GLYF", "Glyph Systems"                               },
02324   { "GOAT", "Dingbat Dungeon"                             },
02325   { "GOGO", "Fonts-A-Go-Go"                               },
02326   { "GPI",  "Gamma Productions"                           },
02327   { "GRIL", "Grilled cheese"                              },
02328   { "HILL", "Hill Systems"                                },
02329   { "HL",   "High-Logic"                                  },
02330   { "HOUS", "House Industries"                            },
02331   { "HP",   "Hewlett-Packard"                             },
02332   { "HS",   "HermesSOFT"                                  },
02333   { "HY",   "HanYang System"                              },
02334   { "IBM",  "IBM"                                         },
02335   { "IDAU", "IDAutomation"                                },
02336   { "IDEE", "IDEE TYPOGRAFICA"                            },
02337   { "IDF",  "International Digital Fonts"                 },
02338   { "ILP",  "Indigenous Language Project"                 },
02339   { "IMPR", "Impress"                                     },
02340   { "INVC", "Invoice Central"                             },
02341   { "ITF",  "International TypeFounders"                  },
02342   { "KATF", "Kingsley/ATF"                                },
02343   { "KUBA", "Kuba Tatarkiewicz"                           },
02344   { "LARA", "Larabiefonts"                                },
02345   { "LEAF", "Interleaf"                                   },
02346   { "LETR", "Letraset"                                    },
02347   { "LGX",  "Logix Research Institute"                    },
02348   { "LING", "Linguist's Software"                         },
02349   { "LINO", "Linotype"                                    },
02350   { "LP",   "LetterPerfect Fonts"                         },
02351   { "LTRX", "Lighttracks"                                 },
02352   { "MACR", "Macromedia"                                  },
02353   { "MATS", "Match Fonts"                                 },
02354   { "MC",   "Cerajewski Computer Consulting"              },
02355   { "MEIR", "Meir Sadan"                                  },
02356   { "MF",   "Magic Fonts"                                 },
02357   { "MFNT", "Masterfont"                                  },
02358   { "MILL", "Millan"                                      },
02359   { "MJ",   "Majus"                                       },
02360   { "MJR",  "Majur"                                       },
02361   { "MLGC", "Micrologic Software"                         },
02362   { "MONO", "Agfa Monotype"                               },
02363   { "MOON", "Moonlight Type and Technolog"                },
02364   { "MS",   "Microsoft"                                   },
02365   { "MSCR", "Majus"                                       },
02366   { "MSE",  "MSE-iT"                                      },
02367   { "MT",   "Agfa Monotype"                               },
02368   { "MTY",  "Motoya"                                      },
02369   { "MUTF", "Murasu Systems Sdn. Bhd"                     },
02370   { "MYFO", "MyFonts"                                     },
02371   { "NB",   "No Bodoni Typography"                        },
02372   { "NDTC", "Neufville Digital"                           },
02373   { "NEC",  "NEC"                                         },
02374   { "NIS",  "NIS"                                         },
02375   { "ORBI", "Orbit Enterprises"                           },
02376   { "P22",  "P22"                                         },
02377   { "PARA", "ParaType"                                    },
02378   { "PDWX", "Parsons Design Workx"                        },
02379   { "PF",   "Phil's Fonts"                                },
02380   { "PLAT", "PLATINUM technology"                         },
02381   { "PRFS", "Production First Software"                   },
02382   { "PSY",  "PSY/OPS"                                     },
02383   { "PTF",  "Porchez Typofonderie"                        },
02384   { "PTMI", "Page Technology Marketing"                   },
02385   { "PYRS", "Pyrus"                                       },
02386   { "QMSI", "QMS/Imagen"                                  },
02387   { "RKFN", "R K Fonts"                                   },
02388   { "robo", "Buro Petr van Blokland"                      },
02389   { "RRT",  "Red Rooster Typefounders"                    },
02390   { "RUDY", "RudynFluffy"                                 },
02391   { "RYOB", "Ryobi"                                       },
02392   { "SAX",  "s.a.x. Software"                             },
02393   { "Sean", "The FontSite"                                },
02394   { "SFUN", "Software Union"                              },
02395   { "SG",   "Scooter Graphics"                            },
02396   { "SHFT", "Shift"                                       },
02397   { "SIG",  "Signature Software"                          },
02398   { "SIL",  "SIL International"                           },
02399   { "SIT",  "Summit Information Technologies"             },
02400   { "skz",  "Celtic Lady's Fonts"                         },
02401   { "SN",   "SourceNet"                                   },
02402   { "SOHO", "Soft Horizons"                               },
02403   { "SOS",  "Standing Ovations Software"                  },
02404   { "STF",  "Brian Sooy + Sooy Type Foundry"              },
02405   { "SUNW", "sunwalk fontworks"                           },
02406   { "SWFT", "Swfte International"                         },
02407   { "SYN",  "SynFonts"                                    },
02408   { "SYRC", "Syriac Computing Institute"                  },
02409   { "TDR",  "Tansin A. Darcos"                            },
02410   { "TERM", "Terminal Design"                             },
02411   { "TF",   "Treacyfaces / Headliners"                    },
02412   { "TILD", "Tilde, SIA"                                  },
02413   { "TIRO", "Tiro Typeworks"                              },
02414   { "TMF",  "The MicroFoundry"                            },
02415   { "TPTC", "Test Pilot Collective"                       },
02416   { "TR",   "Type Revivals"                               },
02417   { "TS",   "TamilSoft"                                   },
02418   { "TTG",  "Twardoch Typography"                         },
02419   { "TYPE", "TypeGroup"                                   },
02420   { "TYPO", "Typodermic"                                  },
02421   { "UA",   "UnAuthorized Type"                           },
02422   { "UNKN", "Unknown Vendor"                              },
02423   { "URW",  "URW++"                                       },
02424   { "UT",   "Unitype"                                     },
02425   { "VKP",  "Vijay K. Patel"                              },
02426   { "VLKF", "Visualogik Technology & Design"              },
02427   { "VOG",  "Martin Vogel"                                },
02428   { "VROM", "Vladimir Romanov"                            },
02429   { "VT",   "VISUALTYPE SRL"                              },
02430   { "WASP", "Wasp barcode"                                },
02431   { "WM",   "Webmakers India"                             },
02432   { "XFC",  "Xerox Font Services"                         },
02433   { "Y&Y",  "Y&Y"                                         },
02434   { "ZeGr", "Zebra Font Factory"                          },
02435   { "zeta", "Tangram Studio"                              },
02436   { "ZSFT", "Zsoft"                                       },
02437   { nsnull,  nsnull                                       },
02438 };
02439  
02440 
02441 // TODO: what TT_OS2_CPR1_OEM standard for. use "oem" temporarily.
02442 nsulCodePageRangeLanguage ulCodePageRange1Language[] = {
02443 { TT_OS2_CPR1_LATIN1 | TT_OS2_CPR1_MAC_ROMAN,     "x-western"           },
02444 { TT_OS2_CPR1_LATIN2,                             "x-central-euro"      },
02445 { TT_OS2_CPR1_CYRILLIC,                           "x-cyrillic"          },
02446 { TT_OS2_CPR1_GREEK,                              "el"                  },
02447 { TT_OS2_CPR1_TURKISH,                            "tr"                  },
02448 { TT_OS2_CPR1_HEBREW,                             "he"                  },
02449 { TT_OS2_CPR1_ARABIC,                             "ar"                  },
02450 { TT_OS2_CPR1_BALTIC,                             "x-baltic"            },
02451 { TT_OS2_CPR1_VIETNAMESE,                         "vietnamese"          },
02452 { TT_OS2_CPR1_THAI,                               "th"                  },
02453 { TT_OS2_CPR1_JAPANESE,                           "ja"                  },
02454 { TT_OS2_CPR1_CHINESE_SIMP,                       "zh-cn"               },
02455 { TT_OS2_CPR1_KO_WANSUNG | TT_OS2_CPR1_KO_JOHAB,  "ko"                  },
02456 { TT_OS2_CPR1_CHINESE_TRAD,                       "zh-tw"               },
02457 { TT_OS2_CPR1_OEM,                                "oem"                 },
02458 { TT_OS2_CPR1_SYMBOL,                             "symbol"              },
02459 { 0,                                              nsnull                },
02460 };
02461 
02462 nsulCodePageRangeLanguage ulCodePageRange2Language[] = {
02463 { TT_OS2_CPR2_GREEK | TT_OS2_CPR2_GREEK_437G,     "el"                  },
02464 { TT_OS2_CPR2_RUSSIAN,                            "x-cyrillic"          },
02465 { TT_OS2_CPR2_NORDIC,                             "x-western"           },
02466 { TT_OS2_CPR2_ARABIC | TT_OS2_CPR2_ARABIC_708,    "ar"                  },
02467 { TT_OS2_CPR2_CA_FRENCH,                          "x-western"           },
02468 { TT_OS2_CPR2_HEBREW,                             "he"                  },
02469 { TT_OS2_CPR2_ICELANDIC,                          "icelandic"           },
02470 { TT_OS2_CPR2_PORTUGESE,                          "x-western"           },
02471 { TT_OS2_CPR2_TURKISH,                            "tr"                  },
02472 { TT_OS2_CPR2_CYRILLIC,                           "x-cyrillic"          },
02473 { TT_OS2_CPR2_LATIN2,                             "x-central-euro"      },
02474 { TT_OS2_CPR2_BALTIC,                             "x-baltic"            },
02475 { TT_OS2_CPR2_WE_LATIN1 || TT_OS2_CPR2_US,        "x-western"           },
02476 { 0,                                              nsnull                },
02477 };
02478 #endif /* #if (!defined(MOZ_ENABLE_FREETYPE2)) */