/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ex: set tabstop=8 softtabstop=2 shiftwidth=2 expandtab: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Brian Stell * * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "gfx-config.h" #include "nsFT2FontCatalog.h" #include "nsFontDebug.h" PRUint32 gFontDebug = 0 | NS_FONT_DEBUG_FONT_SCAN; #if (defined(MOZ_ENABLE_FREETYPE2)) #include #include #include #include #include #include #include #include "nsAppDirectoryServiceDefs.h" #include "nsLocalFile.h" #include "nsIEnumerator.h" #include "nsITimelineService.h" #include "nsArray.h" // // Short overview: // This code is here primarily to solve this problem: getting the list // of valid glyphs in a TrueType font is very expensive when using // the FreeType2 library. To solve this problem this code looks for // a pre-built summary file in the font dir. If this font summary // file is missing it is built and stored in the font dir if possible // so it need not be generated by every user. If the user cannot write // in the font dir the summary is stored in a per-user dir // (ie: $HOME/.mozilla/fontsummaries). // // The routines are in alphabetic order to assist people reading // this code printed on paper in finding the routines. // // The interesting high level entry points are: // // nsFT2FontCatalog::InitGlobals(); // Called during startup to read (and update) the font catalog(s). // // nsFT2FontCatalog::GetFontNames(); // Called when the font code is looking for a font. // // Some interesting low level entry points are: // // nsFT2FontCatalog::NewFceFromFontFile(); // Called to get a TrueType font summary. // Uses FreeType2 to actually open the font file. // This checks for invalid glyphs so this can take a while. // The summary will later be stored in the disk font catalog. // // nsFT2FontCatalog::NewFceFromSummary(); // Called to get the TrueType font summary from the disk font catalog. // // Solaris is missing a prototype for ctime extern "C" {char *ctime(const time_t *timep);} #include #include FT_GLYPH_H #include FT_FREETYPE_H #include FT_TRUETYPE_TABLES_H #include FT_TRUETYPE_IDS_H // these should be static but the compilier complains extern nsFontVendorName sVendorNamesList[]; extern nsulCodePageRangeLanguage ulCodePageRange1Language[]; extern nsulCodePageRangeLanguage ulCodePageRange2Language[]; nsHashtable* nsFT2FontCatalog::sVendorNames = nsnull; nsIPref* nsFT2FontCatalog::sPref = nsnull; #endif // // Implementation of Interfaces nsIFontCatalogService // NS_IMPL_ISUPPORTS1(nsFT2FontCatalog, nsIFontCatalogService) nsFT2FontCatalog::nsFT2FontCatalog() #ifdef MOZ_ENABLE_FREETYPE2 : mFontCatalog(nsnull), mRange1Language(nsnull), mRange2Language(nsnull) #endif { #if (defined(MOZ_ENABLE_FREETYPE2)) nsresult rv; mAvailableFontCatalogService = PR_FALSE; mFt2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv); if (NS_FAILED(rv)) { // FreeType is not available return; } FT_Library lib; mFt2->GetLibrary(&lib); if (!lib) { // FreeType is not available return; } if (!InitGlobals(lib)) { // Font Catalog Service is not available return; } mAvailableFontCatalogService = PR_TRUE; #endif } nsFT2FontCatalog::~nsFT2FontCatalog() { #if (defined(MOZ_ENABLE_FREETYPE2)) FreeGlobals(); #endif } NS_IMETHODIMP nsFT2FontCatalog::GetFontCatalogEntries(const nsACString & aFamilyName, const nsACString & aLanguage, PRUint16 aWeight, PRUint16 aWidth, PRUint16 aSlant, PRUint16 aSpacing, nsIArray **_retval) { #if (!defined(MOZ_ENABLE_FREETYPE2)) *_retval = nsnull; return NS_OK; #else if (mAvailableFontCatalogService == PR_FALSE) { *_retval = nsnull; return NS_OK; } nsFontCatalog *fc = NewFontCatalog(); if (!fc) return NS_ERROR_OUT_OF_MEMORY; GetFontNames(aFamilyName, aLanguage, aWeight, aWidth, aSlant, aSpacing, fc); nsCOMPtr aFce; nsCOMPtr genericFce; nsCOMPtr entries; NS_NewArray(getter_AddRefs(entries)); if (!entries) return NS_ERROR_OUT_OF_MEMORY; int i; for (i = 0; i < fc->numFonts; i++) { aFce = nsFreeTypeGetFaceID(fc->fonts[i]); genericFce = do_QueryInterface(aFce); entries->InsertElementAt(genericFce, 0, PR_FALSE); } free(fc->fonts); free(fc); *_retval = entries; NS_ADDREF(*_retval); #endif return NS_OK; } //-------------------------------------------------- #if (defined(MOZ_ENABLE_FREETYPE2)) void nsFT2FontCatalog::AddDir(nsDirCatalog *dc, nsDirCatalogEntry *dir) { if (dc->numDirs >= dc->numSlots) { dc->numSlots += PR_MAX(1, PR_MIN(dc->numDirs, 128)); dc->dirs = (nsDirCatalogEntry **)realloc(dc->dirs, dc->numSlots*sizeof(nsDirCatalogEntry *)); } dc->dirs[dc->numDirs] = dir; dc->numDirs++; } PRBool nsFT2FontCatalog::AddFceIfCurrent(const char *aFileName, nsHashtable* aFceHash, PRInt64 aFileModTime, nsFontCatalog *aFontCatalog) { int i; nsCStringKey key(aFileName); // // get it from the font summaries // nsFontCatalogEntry *fce = (nsFontCatalogEntry *)aFceHash->Get(&key); if (!fce) return PR_FALSE; // // Check the time // PRInt64 fs_modtime = fce->mMTime; LL_DIV(aFileModTime, aFileModTime, 1000); // microsec -> millisec if (LL_NE(aFileModTime, fs_modtime)) return PR_FALSE; // // Move to the font catalog // aFceHash->Remove(&key); AddFont(aFontCatalog, fce); // // get other faces of the font // for (i=1; imNumFaces; i++) { nsCAutoString key_str(aFileName); // We use this hash when we are checking the files' timestamp. // Since we do not want to open the file we cannot use the // ttc face names (we would need to open the font to get that). // So for the key we append a slash and number to give us a unique key // for each ttc face. char buf[20]; sprintf(buf, "/%d", i); key_str.Append(buf); key = key_str; fce = (nsFontCatalogEntry *)aFceHash->Get(&key); NS_ASSERTION(fce, "additional font faces missing"); if (!fce) { FONT_CATALOG_PRINTF(("missing font face %d, %s", i, aFileName)); return PR_FALSE; } aFceHash->Remove(&key); AddFont(aFontCatalog, fce); } return PR_TRUE; } void nsFT2FontCatalog::AddFont(nsFontCatalog *fc, nsFontCatalogEntry *fce) { if (fc->numFonts >= fc->numSlots) { fc->numSlots += PR_MAX(1, PR_MIN(fc->numFonts, 128)); fc->fonts = (nsFontCatalogEntry **)realloc(fc->fonts, fc->numSlots*sizeof(nsFontCatalogEntry *)); } fc->fonts[fc->numFonts] = fce; fc->numFonts++; } int nsFT2FontCatalog::CheckFontSummaryVersion(nsNameValuePairDB *aDB) { const char *type, *name, *value; unsigned int num, major, minor, rev; int result = FC_FILE_GARBLED; if (aDB->GetNextGroup(&type, FONT_SUMMARY_VERSION_TAG)) { while (aDB->GetNextElement(&name, &value) > 0) { if (*name == '\0') // ignore comments continue; if (strcmp(name, "Version")==0) { num = sscanf(value, "%u.%u.%u", &major, &minor, &rev); if (num != 3) { FONT_CATALOG_PRINTF(("failed to parse version number (%s)", value)); return result; } // FONT_SUMMARY_VERSION_MAJOR // It is presumed that major versions are not backwards compatibile. if (major == FONT_SUMMARY_VERSION_MAJOR) result = FC_FILE_OKAY; else FONT_CATALOG_PRINTF(("version major %d != %d", major, FONT_SUMMARY_VERSION_MAJOR)); // FONT_SUMMARY_VERSION_MINOR // If there is a backwards compatibility with different // minor versions put the test here. // FONT_SUMMARY_VERSION_REV // if there should not be backwards compatibility issues // with different revisions. } } } return result; } #ifdef DEBUG void nsFT2FontCatalog::DumpFontCatalog(nsFontCatalog *fc) { int i; for (i=0; inumFonts; i++) { nsFontCatalogEntry *fce; fce = fc->fonts[i]; if (!fce->mFlags&FCE_FLAGS_ISVALID) continue; DumpFontCatalogEntry(fce); } } #endif #ifdef DEBUG void nsFT2FontCatalog::DumpFontCatalogEntry(nsFontCatalogEntry *fce) { printf(" fce->mFontFileName = %s\n", fce->mFontFileName); printf(" fce->mMTime = %ld %s", fce->mMTime,ctime(&fce->mMTime)); printf(" fce->mFlags = 0x%08x\n", fce->mFlags); printf(" fce->mFaceIndex = %d\n", fce->mFaceIndex); printf(" fce->mNumFaces = %d\n", fce->mNumFaces); printf(" fce->mFontType = %s\n", fce->mFontType); printf(" fce->mFamilyName = %s\n", fce->mFamilyName); printf(" fce->mStyleName = %s\n", fce->mStyleName); printf(" fce->mNumGlyphs = %d\n", fce->mNumGlyphs); printf(" fce->mNumUsableGlyphs = %d\n", fce->mNumUsableGlyphs); printf(" fce->mFaceFlags = 0x%08lx\n", fce->mFaceFlags); printf(" fce->mStyleFlags = 0x%08lx\n", fce->mStyleFlags); printf(" style: "); printf("%s, ", fce->mStyleFlags & FT_STYLE_FLAG_ITALIC ? "italic" : "roman"); printf("%s", fce->mStyleFlags & FT_STYLE_FLAG_BOLD ? "bold" : "regular"); printf("\n"); printf(" fce->mWeight = %d\n", fce->mWeight); printf(" fce->mWidth = %d\n", fce->mWidth); printf(" lang groups (0x%08lx, 0x%08lx): ", fce->mCodePageRange1, fce->mCodePageRange2); if ((fce->mCodePageRange1 == 0) && (fce->mCodePageRange2 == 0)) { printf("guessing latin1 (%d glyphs)", fce->mNumGlyphs); if (fce->mNumGlyphs > 300) { printf("why no lang groups for %s (%s) and so many (%d) glyphs \n", fce->mFamilyName, fce->mFontFileName, fce->mNumGlyphs); } } if ((fce->mCodePageRange1 & TT_OS2_CPR1_LATIN1) || (fce->mCodePageRange1 & TT_OS2_CPR1_MAC_ROMAN) || (fce->mCodePageRange2 & TT_OS2_CPR2_WE_LATIN1) || (fce->mCodePageRange2 & TT_OS2_CPR2_US)) printf("latin1 (iso8859-1), "); if ((fce->mCodePageRange1 & TT_OS2_CPR1_LATIN2) || (fce->mCodePageRange2 & TT_OS2_CPR2_LATIN2)) printf("latin2 (iso8859-2), "); if ((fce->mCodePageRange1 & TT_OS2_CPR1_CYRILLIC) || (fce->mCodePageRange2 & TT_OS2_CPR2_CYRILLIC)) printf("cyrillic (iso8859-5), "); if ((fce->mCodePageRange1 & TT_OS2_CPR1_GREEK) || (fce->mCodePageRange2 & TT_OS2_CPR2_GREEK) || (fce->mCodePageRange2 & TT_OS2_CPR2_GREEK_437G)) printf("greek (iso8859-7), "); if ((fce->mCodePageRange1 & TT_OS2_CPR1_TURKISH) || (fce->mCodePageRange2 & TT_OS2_CPR2_TURKISH)) printf("turkish (iso8859-9), "); if ((fce->mCodePageRange1 & TT_OS2_CPR1_HEBREW) || (fce->mCodePageRange2 & TT_OS2_CPR2_HEBREW)) printf("hebrew (iso8859-8), "); if ((fce->mCodePageRange1 & TT_OS2_CPR1_ARABIC) || (fce->mCodePageRange2 & TT_OS2_CPR2_ARABIC) || (fce->mCodePageRange2 & TT_OS2_CPR2_ARABIC_708)) printf("arabic (iso8859-6), "); if ((fce->mCodePageRange1 & TT_OS2_CPR1_BALTIC) || (fce->mCodePageRange2 & TT_OS2_CPR2_BALTIC)) printf("baltic (iso8859-4), "); if (fce->mCodePageRange1 & TT_OS2_CPR1_VIETNAMESE) printf("vietnamese (viscii1.1-1), "); if (fce->mCodePageRange1 & TT_OS2_CPR1_THAI) printf("thai (tis620.2533-1), "); if (fce->mCodePageRange1 & TT_OS2_CPR1_JAPANESE) printf("japanese (jisx0208.1990-0), "); if (fce->mCodePageRange1 & TT_OS2_CPR1_CHINESE_SIMP) printf("simplified Chinese (gb2312.1980-1), "); if ((fce->mCodePageRange1 & TT_OS2_CPR1_KO_WANSUNG) || (fce->mCodePageRange1 & TT_OS2_CPR1_KO_JOHAB)) printf("korean (ksc5601.1992-3), "); if (fce->mCodePageRange1 & TT_OS2_CPR1_CHINESE_TRAD) printf("traditional Chinese (big5-0), "); if (fce->mCodePageRange1 & TT_OS2_CPR1_SYMBOL) printf("symbol (misc-fontspecific), "); if (fce->mCodePageRange2 & TT_OS2_CPR2_RUSSIAN) printf("russian (koi8-r), "); if (fce->mCodePageRange2 & TT_OS2_CPR2_NORDIC) printf("nordic (iso8859-10), "); if (fce->mCodePageRange2 & TT_OS2_CPR2_CA_FRENCH) printf("canadian french (iso8859-1), "); if (fce->mCodePageRange2 & TT_OS2_CPR2_ICELANDIC) printf("icelandic (iso8859-1), "); if (fce->mCodePageRange2 & TT_OS2_CPR2_PORTUGESE) printf("portugese (iso8859-1), "); printf("\n"); printf(" fce->mVendorID = %4s\n", fce->mVendorID); printf(" fce->mFoundryName = %s\n", fce->mFoundryName); printf(" fce->mEmbeddedBitmapHeights="); for (int i=0; imNumEmbeddedBitmaps; i++) printf("%d,", fce->mEmbeddedBitmapHeights[i]); printf("\n"); printCCMap(fce->mCCMap); } #endif void nsFT2FontCatalog::FixUpFontCatalog(nsFontCatalog *fc) { int i; for (i=0; inumFonts; i++) { nsFontCatalogEntry *fce; fce = fc->fonts[i]; if (!fce->mFlags&FCE_FLAGS_ISVALID) continue; // some TrueType fonts seem to have weights in the 1 to 9 range if ((fce->mWeight>=1) && (fce->mWeight<=9)) { if (mIsNewCatalog) FONT_CATALOG_PRINTF(("change weight from %d to %d, %s", fce->mWeight, fce->mWeight*100, fce->mFamilyName)); fce->mWeight *= 100; } if ((fce->mWeight<100) || (fce->mWeight>900)) { FONT_CATALOG_PRINTF(("invalid weight %d, %s", fce->mWeight, fce->mFamilyName)); fce->mFlags &= ~FCE_FLAGS_ISVALID; continue; } if (fce->mWidth>8) { FONT_CATALOG_PRINTF(("limit width from %d to 8, %s", fce->mWidth, fce->mFamilyName)); fce->mWidth = 8; } nsCAutoString familyName(fce->mFamilyName); free((void*)fce->mFamilyName); ToLowerCase(familyName); // nsFontMetricsGTK (like XLFD) does not allow a dash in the name familyName.ReplaceChar('-', ' '); fce->mFamilyName = strdup(familyName.get()); if (!fce->mFamilyName) { fce->mFlags &= ~FCE_FLAGS_ISVALID; continue; } nsCAutoString vendorID(fce->mVendorID); ToLowerCase(vendorID); vendorID.StripChars(" "); nsCStringKey key(vendorID); const char *vendorStr = (const char *)sVendorNames->Get(&key); if (!vendorStr) { if (fce->mVendorID[0]) vendorStr = fce->mVendorID; else vendorStr = ""; } nsCAutoString vendorName(vendorStr); ToLowerCase(vendorName); fce->mFoundryName = strdup(vendorName.get()); if (!fce->mFoundryName) { fce->mFlags &= ~FCE_FLAGS_ISVALID; continue; } if ((fce->mCodePageRange1==0) && (fce->mCodePageRange2==0) && !(fce->mFlags&FCE_FLAGS_SYMBOL)) { // no lang group set so try guessing Latin1 NS_ASSERTION(fce->mNumGlyphs<=300, "font has no lang group bits set AND has over 300 glyphs"); if (fce->mNumGlyphs>300) FONT_CATALOG_PRINTF(("no CodePageRange bits but %d glyphs, %s", fce->mNumGlyphs, fce->mFamilyName)); fce->mCodePageRange1 |= TT_OS2_CPR1_LATIN1; } } } PRBool nsFT2FontCatalog::FreeFceHashEntry(nsHashKey* aKey, void* aData, void* aClosure) { nsFontCatalogEntry *fce = (nsFontCatalogEntry *)aData; FreeFontCatalogEntry(fce); return PR_TRUE; } void nsFT2FontCatalog::FreeFontCatalog(nsFontCatalog *fc) { int i; for (i=0; inumFonts; i++) { nsFontCatalogEntry *fce; fce = fc->fonts[i]; FreeFontCatalogEntry(fce); } free(fc->fonts); free(fc); } void nsFT2FontCatalog::FreeDirCatalog(nsDirCatalog *dc) { int i; for (i=0; inumDirs; i++) { nsDirCatalogEntry *dce; dce = dc->dirs[i]; FreeDirCatalogEntry(dce); } free(dc->dirs); free(dc); } void nsFT2FontCatalog::FreeDirCatalogEntry(nsDirCatalogEntry *dce) { if (!dce) { NS_ASSERTION(dce, "dce is null"); return; } FREE_IF(dce->mDirName); free(dce); } void nsFT2FontCatalog::FreeFontCatalogEntry(nsFontCatalogEntry *fce) { if (!fce) { NS_ASSERTION(fce, "fce is null"); return; } FREE_IF(fce->mFontFileName); FREE_IF(fce->mFontType); FREE_IF(fce->mFamilyName); FREE_IF(fce->mStyleName); FREE_IF(fce->mFoundryName); FREE_IF(fce->mEmbeddedBitmapHeights); if (fce->mCCMap) FreeCCMap(fce->mCCMap); free(fce); } void nsFT2FontCatalog::FreeGlobals() { if (mFontCatalog) { FreeFontCatalog(mFontCatalog); mFontCatalog = nsnull; } // sVendorNames elements are not alloc'd so no need call Reset delete sVendorNames; delete mRange1Language; delete mRange2Language; NS_IF_RELEASE(sPref); } void nsFT2FontCatalog::GetDirsPrefEnumCallback(const char* aName, void* aClosure) { nsDirCatalog *dirCatalog = (nsDirCatalog *)aClosure; nsDirCatalogEntry *dce; dce = (nsDirCatalogEntry *)calloc(1, sizeof(nsDirCatalogEntry)); if (!dce) return; // native charset?! sPref->CopyCharPref(aName, (char **)&dce->mDirName); if (!dce->mDirName) return; AddDir(dirCatalog, dce); } PRInt32 * nsFT2FontCatalog::GetEmbeddedBitmapHeights(nsFontCatalogEntry *aFce) { return aFce->mEmbeddedBitmapHeights; } PRInt32 nsFT2FontCatalog::GetFaceIndex(nsFontCatalogEntry *aFce) { return aFce->mFaceIndex; } const char* nsFT2FontCatalog::GetFamilyName(nsFontCatalogEntry *aFce) { return aFce->mFamilyName; } const char* nsFT2FontCatalog::GetFileName(nsFontCatalogEntry *aFce) { return aFce->mFontFileName; } int nsFT2FontCatalog::GetFontCatalog(FT_Library lib, nsFontCatalog *aFontCatalog, nsDirCatalog *aOldDirCatalog) { int i; nsresult rv; nsCAutoString font_summaries_dir_path; nsCAutoString font_download_dir_path; PRBool exists; nsCOMPtr font_summaries_dir, font_download_dir; if (lib) { // // Get the dir for downloaded fonts // rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(font_download_dir)); if (NS_FAILED(rv)) goto cleanup_and_return; rv = font_download_dir->AppendNative(FONT_DOWNLOAD_SUBDIR); if (NS_FAILED(rv)) goto cleanup_and_return; exists = PR_FALSE; rv = font_download_dir->Exists(&exists); if (NS_FAILED(rv)) goto cleanup_and_return; if (!exists) { rv = font_download_dir->Create(nsIFile::DIRECTORY_TYPE, 0775); if (NS_FAILED(rv)) goto cleanup_and_return; } rv = font_download_dir->GetNativePath(font_download_dir_path); if (NS_FAILED(rv)) goto cleanup_and_return; // // Get the user dir for font catalogs // rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(font_summaries_dir)); if (NS_FAILED(rv)) goto cleanup_and_return; rv = font_summaries_dir->AppendNative(FONT_DOWNLOAD_SUBDIR); if (NS_FAILED(rv)) goto cleanup_and_return; rv = font_summaries_dir->AppendNative(FONT_SUMMARIES_SUBDIR); if (NS_FAILED(rv)) goto cleanup_and_return; exists = PR_FALSE; rv = font_summaries_dir->Exists(&exists); if (NS_FAILED(rv)) goto cleanup_and_return; if (!exists) { rv = font_summaries_dir->Create(nsIFile::DIRECTORY_TYPE, 0775); if (NS_FAILED(rv)) goto cleanup_and_return; } rv = font_summaries_dir->GetNativePath(font_summaries_dir_path); if (NS_FAILED(rv)) goto cleanup_and_return; // // Get the font summaries for the public font dirs // for (i=0; inumDirs; i++) { HandleFontDir(lib, aFontCatalog, font_summaries_dir_path, nsDependentCString(aOldDirCatalog->dirs[i]->mDirName)); } // // Get the font summaries for the downloaded/private font dir // HandleFontDir(lib, aFontCatalog, font_summaries_dir_path, font_download_dir_path); } return 0; cleanup_and_return: FONT_CATALOG_PRINTF(("nsFT2FontCatalog::GetFontCatalog failed")); return -1; } void nsFT2FontCatalog::GetFontNames(const nsACString & aFamilyName, const nsACString & aLanguage, PRUint16 aWeight, PRUint16 aWidth, PRUint16 aSlant, PRUint16 aSpacing, nsFontCatalog* aFC) { int i; PRUint16 min_weight = PR_MAX(0, aWeight-125); PRUint16 max_weight = PR_MIN(999, aWeight+125); nsCAutoString familyName, language; FONT_CATALOG_PRINTF(("looking for FreeType font matching")); ToLowerCase(aFamilyName, familyName); ToLowerCase(aLanguage, language); FONT_CATALOG_PRINTF(("familyName=%s; language=%s; " "weight=%d; width=%d; slant=%d; spacing=%d", familyName.get(), language.get(), aWeight, aWidth, aSlant, aSpacing)); unsigned long bit1 = GetRangeLanguage(language, CPR1); unsigned long bit2 = GetRangeLanguage(language, CPR2); PRUint16 italicBit = 0; switch (aSlant) { case kFCSlantRoman: break; case kFCSlantItalic: case kFCSlantOblique: case kFCSlantReverseItalic: case kFCSlantReverseOblique: italicBit = 1; break; default: break; } PRUint16 monoBit = 0; switch (aSpacing) { case kFCSpacingMonospace: monoBit = 0; break; case kFCSpacingProportional: monoBit = 1; break; default: break; } /* column headers for the debug output*/ FONT_CATALOG_PRINTF(("%s\t%-20s\t%-8s\t%-8s\t%-8s%-8s%-8s\t%-8s\t", "mFlags", "mFamilyName", "mCodePageRange1", "mCodePageRange2", "mWeight", "mWidth", "mStyleFlags", "fce->mFaceFlags")); for (i=0; inumFonts; i++) { nsFontCatalogEntry *fce = mFontCatalog->fonts[i]; // not all "fce" are valid if (!fce->mFlags&FCE_FLAGS_ISVALID) continue; // family if (!familyName.IsEmpty() && !familyName.Equals(fce->mFamilyName)) continue; // language if (!language.IsEmpty() && !((fce->mCodePageRange1 & bit1) || (fce->mCodePageRange2 & bit2))) continue; // weight (the meaning is not well defined so allow some variance) if ((aWeight != kFCWeightAny) && ((fce->mWeight < min_weight) || (fce->mWeight > max_weight))) continue; // width if ((aWidth != kFCWidthAny) && (aWidth != fce->mWidth)) continue; // slant if ((aSlant != kFCSlantAny) && !((fce->mStyleFlags & FT_STYLE_FLAG_ITALIC) == italicBit)) continue; // spacing if ((aSpacing != kFCSpacingAny) && !((fce->mFaceFlags & FT_FACE_FLAG_FIXED_WIDTH) == monoBit)) continue; // match all patterns FONT_CATALOG_PRINTF(("%0x\t%-20s\t%08lx\t%08lx\t%i\t%i\t%08lx\t%08lx", fce->mFlags, fce->mFamilyName, fce->mCodePageRange1, fce->mCodePageRange2, fce->mWeight, fce->mWidth, fce->mStyleFlags, fce->mFaceFlags)); AddFont(aFC, fce); } return; } PRBool nsFT2FontCatalog::GetFontSummaryName(const nsACString &aFontDirName, // native charset const nsACString &aFontSummariesDir, // native charset nsACString &aFontSummaryFileName, nsACString &aFallbackFontSummaryFileName) { int error; struct stat file_info; PRBool exists = PR_FALSE; PRBool public_dir_writable = PR_FALSE; PRBool public_summary_writable = PR_FALSE; nsresult rv; nsCOMPtr font_dir; // // see if we should use the "public" one in the font dir itself // or the "private" one in our $HOME/.mozilla/fontsummaries dir // font_dir = new nsLocalFile(); font_dir->InitWithNativePath(aFontDirName); rv = font_dir->IsWritable(&public_dir_writable); if (NS_SUCCEEDED(rv) && public_dir_writable) { FONT_CATALOG_PRINTF(("can write \"%s\"", PromiseFlatCString(aFontDirName).get())); nsCOMPtr summary_file = new nsLocalFile(); summary_file->InitWithNativePath(aFontDirName); summary_file->AppendNative(PUBLIC_FONT_SUMMARY_NAME); nsCAutoString font_summary_path; summary_file->GetNativePath(font_summary_path); FONT_CATALOG_PRINTF(("font_summary_path = \"%s\"", font_summary_path.get())); rv = summary_file->Exists(&exists); if (NS_SUCCEEDED(rv)) { if (!exists) { public_summary_writable = PR_TRUE; aFontSummaryFileName = font_summary_path; } else { FONT_CATALOG_PRINTF(("font summary \"%s\" exists", font_summary_path.get())); rv = summary_file->IsWritable(&public_summary_writable); if (NS_SUCCEEDED(rv) && public_summary_writable) { FONT_CATALOG_PRINTF(("font summary \"%s\" is writable", font_summary_path.get())); public_summary_writable = PR_TRUE; aFontSummaryFileName = font_summary_path; } } } } if (!public_summary_writable) { // // Generate the private font summary name from: // 1) the user's product directory // 2) the font dir's parent dir's device/inode // 3) the font dir's name in that dir // file name = // .d.ndb // eg: for: // user's product dir "/home/bstell/.mozilla/fontsummaries" // the font dir "/home/bstell/tt_font" // where /home/bstell is inode 1234 on device 3,2 // the name would be: // // /home/bstell/.mozilla/fontsummaries/tt_font.d0302.i1234.ndb // // // Split the parent dir and file name // PRInt32 slash = 0, last_slash = -1; // RFindChar not coded so do it by hand while ((slash=aFontDirName.FindChar('/', slash))>=0) { last_slash = slash; slash++; } if (last_slash < 0) { FONT_CATALOG_PRINTF(("did not find a \"/\" in %s", PromiseFlatCString(aFontDirName).get())); return PR_FALSE; } int right_len = aFontDirName.Length() - last_slash - 1; nsCAutoString parent_dir(Substring(aFontDirName, 0, last_slash)); nsCAutoString font_dir_name_tail(Substring(aFontDirName, last_slash+1, right_len)); // // Get the parent dir's device and inode // error = stat(PromiseFlatCString(parent_dir).get(), &file_info); if (error) { FONT_CATALOG_PRINTF(("failed to stat %s", PromiseFlatCString(parent_dir).get())); return PR_FALSE; } int dev = file_info.st_dev; int inode = file_info.st_ino; FONT_CATALOG_PRINTF(("parent dir dev = %04x, inode = %d", dev, inode)); char buf[64]; sprintf(buf, ".d%04x.i%d", dev, inode); font_dir_name_tail.Append(buf); // // Build the font summary name // aFontSummaryFileName = aFontSummariesDir; aFontSummaryFileName.Append("/"); aFontSummaryFileName.Append(font_dir_name_tail); aFontSummaryFileName.Append(FONT_SUMMARIES_EXTENSION); // // Build the backup Font Summary name // aFallbackFontSummaryFileName = aFontDirName; aFallbackFontSummaryFileName.Append("/"); aFallbackFontSummaryFileName.Append(PUBLIC_FONT_SUMMARY_NAME); } return PR_TRUE; } const char * nsFT2FontCatalog::GetFoundry(nsFontCatalogEntry *aFce) { nsCAutoString foundry(aFce->mVendorID); ToLowerCase(foundry); foundry.StripChars(" "); nsCStringKey key(foundry); const char *vendorName = (const char *)sVendorNames->Get(&key); if (!vendorName) { if (aFce->mVendorID[0]) vendorName = aFce->mVendorID; else vendorName = ""; } return vendorName; } PRInt32 nsFT2FontCatalog::GetNumEmbeddedBitmaps(nsFontCatalogEntry *aFce) { return aFce->mNumEmbeddedBitmaps; } PRBool nsFT2FontCatalog::HandleFontDir(FT_Library aFreeTypeLibrary, nsFontCatalog *aFontCatalog, const nsACString &aFontSummariesDir, // native charset const nsACString &aFontDirName) // native charset { int i, status = -1; PRBool rslt, current; nsCAutoString fileName; nsHashtable* fontFileNamesHash = nsnull; nsHashtable* fallbackFceHash = nsnull; nsresult rv; nsCAutoString fontSummaryFilename, fallbackFontSummaryFilename; nsFontCatalog *dirFontCatalog = nsnull; PRBool moreFilesInDir = PR_FALSE; nsCOMPtr dir; nsCOMPtr dirLocal; nsCOMPtr dirEntry; nsCOMPtr dirIterator; PRBool summary_needs_update = PR_FALSE; nsFontCatalogEntry *fce; // // temp holder for the font summaries in this dir // dirFontCatalog = NewFontCatalog(); if (!dirFontCatalog) goto cleanup_and_return; // also hash to quick access fontFileNamesHash = new nsHashtable(); if (!fontFileNamesHash) goto cleanup_and_return; // // Figure out where the font summary is // rslt = GetFontSummaryName(aFontDirName, aFontSummariesDir, fontSummaryFilename, fallbackFontSummaryFilename); if (!rslt) { FONT_CATALOG_PRINTF(("failed to get font summary name for %s %s", PromiseFlatCString(aFontDirName).get(), PromiseFlatCString(aFontSummariesDir).get())); goto cleanup_and_return; } FONT_CATALOG_PRINTF(("for \"%s\":\n font summary = %s" "\n fallback = %s", PromiseFlatCString(aFontDirName).get(), PromiseFlatCString(fontSummaryFilename).get(), fallbackFontSummaryFilename.Length()>0 ? fallbackFontSummaryFilename.get() :"")); // // Get the font summaries // ReadFontDirSummary(fontSummaryFilename, fontFileNamesHash); // // Open the dir // dir = new nsLocalFile(); dirLocal = do_QueryInterface(dir); dirLocal->InitWithNativePath(aFontDirName); rv = dir->GetDirectoryEntries(getter_AddRefs(dirIterator)); if (NS_FAILED(rv)) { FONT_CATALOG_PRINTF(("failed to open dir (get iterator) for %s", PromiseFlatCString(aFontDirName).get())); goto cleanup_and_return; } rv = dirIterator->HasMoreElements(&moreFilesInDir); if (NS_FAILED(rv)) { FONT_CATALOG_PRINTF(("failed HasMoreElements")); goto cleanup_and_return; } // // Compare the files in the dir to the font summaries // while (moreFilesInDir) { PRBool isFile; current = PR_FALSE; rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry)); if (NS_FAILED(rv)) { FONT_CATALOG_PRINTF(("failed GetNext")); goto cleanup_and_return; } //char *path; dirEntry->GetNativePath(fileName); FONT_CATALOG_PRINTF(("dirEntry = \"%s\"", fileName.get())); rv = dirEntry->IsFile(&isFile); if (NS_SUCCEEDED(rv) && isFile) { PRInt64 modtime; dirEntry->GetLastModifiedTime(&modtime); current = AddFceIfCurrent(fileName.get(), fontFileNamesHash, modtime, dirFontCatalog); if (!current) { // Ignore the font summary itself if (fileName.Equals(fontSummaryFilename) || fileName.Equals(fallbackFontSummaryFilename)) { FONT_CATALOG_PRINTF(("font summary %s is not a font", fileName.get())); current = PR_TRUE; } // If not in font summary, try the fallback summary else if (fallbackFontSummaryFilename.Length()) { if (!fallbackFceHash) { fallbackFceHash = new nsHashtable(); if (fallbackFceHash) { ReadFontDirSummary(fallbackFontSummaryFilename, fallbackFceHash); } } if (fallbackFceHash) { summary_needs_update = PR_TRUE; current = AddFceIfCurrent(fileName.get(), fallbackFceHash, modtime, dirFontCatalog); } } // // If not found in font summary or fallback // then scan the font // if (!current) { summary_needs_update = PR_TRUE; HandleFontFile(aFreeTypeLibrary, dirFontCatalog, fileName.get()); } } } rv = dirIterator->HasMoreElements(&moreFilesInDir); if (NS_FAILED(rv)) { FONT_CATALOG_PRINTF(("failed HasMoreElements")); goto cleanup_and_return; } } // // if hash count != 0 then needs update // if (fontFileNamesHash->Count()) { summary_needs_update = PR_TRUE; } // // Check if need to update font summary // if (summary_needs_update) { FONT_CATALOG_PRINTF(("update the font summary")); nsNameValuePairDB tmp_fc; if (!tmp_fc.OpenTmpForWrite(fontSummaryFilename)) return 0; // failed to write but still got font data // print the Font Summary version PrintFontSummaryVersion(&tmp_fc); // print the font summaries PrintFontSummaries(&tmp_fc, dirFontCatalog); if (tmp_fc.HadError()) return 0; // failed to write but still got font data tmp_fc.RenameTmp(PromiseFlatCString(fontSummaryFilename).get()); } // // transfer the fce from this dir to the main font catalog // for (i=0; inumFonts; i++) { fce = dirFontCatalog->fonts[i]; AddFont(aFontCatalog, fce); } dirFontCatalog->numFonts = 0; status = 0; cleanup_and_return: if(dirFontCatalog) FreeFontCatalog(dirFontCatalog); if(fontFileNamesHash) { fontFileNamesHash->Reset(FreeFceHashEntry, nsnull); delete fontFileNamesHash; } if(fallbackFceHash) { fallbackFceHash->Reset(FreeFceHashEntry, nsnull); delete fallbackFceHash; } return status; } void nsFT2FontCatalog::HandleFontFile(FT_Library aFreeTypeLibrary, nsFontCatalog *aFontCatalog, const char *aFontFileName) { int j, num_faces; nsFontCatalogEntry *fce; /* FONT_CATALOG_PRINTF(("handle font %s", aFontFileName)); */ fce = NewFceFromFontFile(aFreeTypeLibrary, aFontFileName, 0, &num_faces); if (!fce) { //FONT_CATALOG_PRINTF(("failed to catalog %s", aFontFileName)); return; } AddFont(aFontCatalog, fce); /* loop thru the additional faces */ for (j=1; jvendorID) { nsCAutoString name(vn->vendorID); ToLowerCase(name); nsCStringKey key(name); sVendorNames->Put(&key, (void*)vn->vendorName); vn++; } mRange1Language = new nsHashtable(); if (!mRange1Language) goto cleanup_and_return; crl = ulCodePageRange1Language; while (crl->language) { nsCStringKey key(crl->language); mRange1Language->Put(&key, &(crl->bit)); crl++; } mRange2Language = new nsHashtable(); if (!mRange2Language) goto cleanup_and_return; crl = ulCodePageRange2Language; while (crl->language) { nsCStringKey key(crl->language); mRange2Language->Put(&key, &(crl->bit)); crl++; } // get dirs list from prefs dirCatalog = NewDirCatalog(); if (!dirCatalog) goto cleanup_and_return; sPref->EnumerateChildren(prefix.get(), GetDirsPrefEnumCallback, dirCatalog); NS_TIMELINE_START_TIMER("nsFT2FontCatalog::GetFontCatalog"); GetFontCatalog(lib, mFontCatalog, dirCatalog); NS_TIMELINE_STOP_TIMER("nsFT2FontCatalog::GetFontCatalog"); NS_TIMELINE_MARK_TIMER("nsFT2FontCatalog::GetFontCatalog"); FreeDirCatalog(dirCatalog); FixUpFontCatalog(mFontCatalog); #ifdef DEBUG if (dump_catalog) DumpFontCatalog(mFontCatalog); #endif #ifdef DEBUG for (i=0; inumFonts; i++) { if (mFontCatalog->fonts[i]->mFlags&FCE_FLAGS_ISVALID) num_ftfonts++; } FONT_CATALOG_PRINTF(("can use %d TrueType fonts (font dirs hold %d files)", num_ftfonts, mFontCatalog->numFonts)); #endif return(PR_TRUE); cleanup_and_return: FONT_CATALOG_PRINTF(("nsFT2FontCatalog::InitGlobals failed")); FreeGlobals(); return(PR_FALSE); } // // Routine to tell if a char should be blank // This routing is simplistic but Erik van der Poel recommended // this and it seems to be sufficient for the windows code; // In the windows code see SHOULD_BE_SPACE_CHAR(ch) // PRBool nsFT2FontCatalog::IsSpace(FT_Long c) { switch (c) { case 0x0020: // ascii space case 0x00A0: // non-breaking space case 0x3000: // ideographic space return PR_TRUE; } // 2000 == EN quad // 2001 == EM quad // 2002 == EN space // 2003 == EM space // 2004 == 3 per EM space // 2005 == 4 per EM space // 2006 == 6 per EM space // 2007 == figure space // 2008 == punction space // 2009 == thin space // 200A == hair space // 200B == zero width space if ((c >= 0x2000) && (c <= 0x200b)) return PR_TRUE; return PR_FALSE; } nsDirCatalog * nsFT2FontCatalog::NewDirCatalog() { nsDirCatalog *dc; dc = (nsDirCatalog *)calloc(1, sizeof(nsDirCatalog)); return dc; } nsFontCatalogEntry * nsFT2FontCatalog::NewFceFromFontFile(FT_Library aFreeTypeLibrary, const char *aFontFileName, int aFaceIndex, int * aNumFaces) { PRUint32 i, len; nsFontCatalogEntry *fce; FT_Error fterror; FT_Face face = nsnull; FT_UInt glyph_index; FT_GlyphSlot slot; TT_OS2 *tt_os2; int error; struct stat file_info; int num_checked = 0; int blank_chars; nsCompressedCharMap ccmapObj; nsresult rv; fce = (nsFontCatalogEntry *)calloc(1, sizeof(nsFontCatalogEntry)); if (!fce) return nsnull; FONT_SCAN_PRINTF(("font %s ", aFontFileName)); if (aFaceIndex) { FONT_SCAN_PRINTF(("face %d ", aFaceIndex+1)); } error = stat(aFontFileName, &file_info); if (error) { FONT_SCAN_PRINTF((" unable to stat font file")); goto cleanup_and_return; } fce->mFontFileName = strdup(aFontFileName); if (!fce->mFontFileName) goto no_memory_cleanup_and_return; fce->mMTime = file_info.st_mtime; fce->mFaceIndex = aFaceIndex; // open the font rv = mFt2->NewFace(aFreeTypeLibrary, aFontFileName, aFaceIndex, &face); if (NS_FAILED(rv)) { FONT_SCAN_PRINTF((" FreeType failed to open, error=%d", fterror)); goto cleanup_and_return; } if (!FT_IS_SCALABLE(face)) { FONT_SCAN_PRINTF((" not scalable, ignoring")); goto cleanup_and_return; } NS_ASSERTION(face->family_name,"font is missing FamilyName"); if (!face->family_name) goto cleanup_and_return; nsTTFontFamilyEncoderInfo *ffei; ffei = nsFreeType2::GetCustomEncoderInfo(face->family_name); if (ffei) { fce->mFlags = FCE_FLAGS_ISVALID | FCE_FLAGS_SYMBOL; } else { for (i=0; i < face->num_charmaps; i++) { if (face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT) { if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS) { fce->mFlags = FCE_FLAGS_ISVALID | FCE_FLAGS_UNICODE; fterror = mFt2->SetCharmap(face, face->charmaps[i]); if (fterror) { FONT_SCAN_PRINTF(("failed to select unicode charmap")); goto cleanup_and_return; } } #if defined(TT_MS_ID_UCS_4) else if (face->charmaps[i]->encoding_id == TT_MS_ID_UCS_4) { fce->mFlags = FCE_FLAGS_ISVALID | FCE_FLAGS_UNICODE | FCE_FLAGS_SURROGATE; fterror = mFt2->SetCharmap(face, face->charmaps[i]); if (fterror) { FONT_SCAN_PRINTF(("failed to select unicode charmap")); goto cleanup_and_return; } break; } #endif } } } if (!fce->mFlags&FCE_FLAGS_ISVALID) { FONT_SCAN_PRINTF(("%s is missing cmap", face->family_name)); goto cleanup_and_return; } mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2); if (!tt_os2) { FONT_SCAN_PRINTF(("unable to get OS2 table")); goto cleanup_and_return; } fce->mFontType = strdup("TrueType"); if (!fce->mFontType) goto no_memory_cleanup_and_return; fce->mWeight = tt_os2->usWeightClass; fce->mWidth = tt_os2->usWidthClass; fce->mCodePageRange1 = tt_os2->ulCodePageRange1; fce->mCodePageRange2 = tt_os2->ulCodePageRange2; // sadly too many fonts have vendor ID blank //NS_ASSERTION(*((char*)tt_os2->achVendID), "invalid vendor id"); memset((char*)fce->mVendorID, 0, sizeof(fce->mVendorID)); strncpy((char*)fce->mVendorID, (char*)tt_os2->achVendID, sizeof(fce->mVendorID)-1); fce->mNumFaces = face->num_faces; if (aNumFaces!=nsnull) *aNumFaces = face->num_faces; //FONT_CATALOG_PRINTF(("family = %s", face->family_name)); fce->mFamilyName = strdup(face->family_name); if (!fce->mFamilyName) goto no_memory_cleanup_and_return; fce->mStyleName = strdup(face->style_name); if (!fce->mStyleName) goto no_memory_cleanup_and_return; fce->mFaceFlags = face->face_flags; fce->mStyleFlags = face->style_flags; fce->mNumGlyphs = face->num_glyphs; fce->mNumEmbeddedBitmaps = face->num_fixed_sizes; if (fce->mNumEmbeddedBitmaps) { fce->mEmbeddedBitmapHeights = (int*)calloc(fce->mNumEmbeddedBitmaps, sizeof(fce->mEmbeddedBitmapHeights[0])); if (!fce->mEmbeddedBitmapHeights) goto no_memory_cleanup_and_return; for (int i=0; imNumEmbeddedBitmaps; i++) fce->mEmbeddedBitmapHeights[i] = face->available_sizes[i].height; } if ((fce->mFlags & FCE_FLAGS_UNICODE) || (fce->mFlags & FCE_FLAGS_SURROGATE)) { if (fce->mFlags & FCE_FLAGS_SURROGATE) { ccmapObj.Extend(); } // check fast methods are defined PRBool has_fast_methods; mFt2->SupportsExtFunc(&has_fast_methods); PRBool scan_done = PR_FALSE; if (has_fast_methods) { mFt2->GetFirstChar(face, &glyph_index, (FT_ULong*)&i); if (glyph_index == 0) { // no glyph in the font scan_done = PR_TRUE; } } else { i=0; } len = NUM_UNICODE_CHARS; if(fce->mFlags & FCE_FLAGS_SURROGATE) { len = 0xFFFFF; } blank_chars = 0; slot = face->glyph; FONT_SCAN_PRINTF((" ")); while (!scan_done && i < len) { if (!has_fast_methods) { mFt2->GetCharIndex(face, (FT_ULong)i, &glyph_index); //FONT_CATALOG_PRINTF(("i=%d, glyph_index=%d", i, glyph_index)); if (glyph_index == 0) { goto next_char; } } if (gFontDebug & NS_FONT_DEBUG_FONT_SCAN) { if ((num_checked % 1000) == 0) { FONT_SCAN_PRINTF(("\b\b\b\b\b\b\b\b\b\b\b\b\b\b%7d glyphs", num_checked)); } } num_checked++; rv = mFt2->LoadGlyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING); //FONT_CATALOG_PRINTF(("fterror = %d", fterror)); if (NS_FAILED(rv)) { FONT_CATALOG_PRINTF(("error loading %d (glyph index = %d)", i, glyph_index)); goto next_char; } if (slot->format == ft_glyph_format_outline) { //FONT_CATALOG_PRINTF(("n_contours=%d", slot->outline.n_contours)); if ((slot->outline.n_contours==0) && (!IsSpace(i))) { blank_chars++; FT_Glyph glyph; FT_BBox bbox; mFt2->GetGlyph(slot, &glyph); mFt2->GlyphGetCBox(glyph, ft_glyph_bbox_pixels, &bbox); mFt2->DoneGlyph(glyph); if((bbox.xMax==0) && (bbox.xMin==0) && (bbox.yMax==0) && (bbox.yMin==0)) { goto next_char; } FONT_SCAN_PRINTF(("no contours %d (glyph index = %d)\n", i, glyph_index)); FONT_CATALOG_PRINTF(("character 0x%04x no contour but glyph has " "non-zero bounding box", i)); NS_WARNING("character no contour but glyph has non-zero bounding box"); } } else if (slot->format == ft_glyph_format_bitmap) { // this "empty bitmap" test is just a guess if ((slot->bitmap.rows==0) || (slot->bitmap.width==0)) { FONT_CATALOG_PRINTF(("no bitmap for glyph 0x%04x", i)); FONT_CATALOG_PRINTF(("continue at line %d", __LINE__)); FONT_SCAN_PRINTF(("empty bitmap %d (glyph index = %d)\n", i, glyph_index)); goto next_char; } } else { NS_WARNING("need to test for empty (non-space char) glyph"); } ccmapObj.SetChar(i); fce->mNumUsableGlyphs++; next_char: if (has_fast_methods) { FT_ULong ncharcode; mFt2->GetNextChar(face, (FT_ULong)i, &glyph_index, &ncharcode); i = ncharcode; if (glyph_index == 0) { // no more glyph in the font scan_done = PR_TRUE; } } else { i++; } } if (gFontDebug & NS_FONT_DEBUG_FONT_SCAN) { FONT_SCAN_PRINTF(("\b\b\b\b\b\b\b\b\b\b\b\b\b\b%7d glyphs", num_checked)); if (blank_chars) { FONT_SCAN_PRINTF((" (%d invalid)", blank_chars)); } } if (fce->mNumUsableGlyphs == 0) fce->mFlags |= FCE_FLAGS_ISVALID; fce->mCCMap = ccmapObj.NewCCMap(); } else if (fce->mFlags & FCE_FLAGS_SYMBOL) { FONT_SCAN_PRINTF(("uses custom encoder")); if (ffei) { nsCOMPtr mapper; mapper = do_QueryInterface(ffei->mEncodingInfo->mConverter); if (mapper) { fce->mCCMap = MapperToCCMap(mapper); } } } else { FONT_SCAN_PRINTF(("unknown font encoding")); } if (!fce->mCCMap) { FONT_CATALOG_PRINTF(("Failed to copy CCMap")); goto cleanup_and_return; } mFt2->DoneFace(face); FONT_SCAN_PRINTF(("\n")); return fce; // regardless of why we could not use the file we want to put it in the // catalog so we do not reopen invalid files every time we startup cleanup_and_return: FONT_CATALOG_PRINTF(("nsFT2FontCatalog::NewFceFromFontFile failed")); fce->mFlags &= ~FCE_FLAGS_ISVALID; fce->mFontType = strdup(""); fce->mNumFaces = 0; if (aNumFaces) *aNumFaces = 0; fce->mFamilyName = strdup(""); fce->mFlags = 0; fce->mStyleName = strdup(""); FREE_IF(fce->mEmbeddedBitmapHeights); if (face) mFt2->DoneFace(face); FONT_SCAN_PRINTF(("\n")); return fce; no_memory_cleanup_and_return: FONT_CATALOG_PRINTF(("nsFT2FontCatalog::NewFceFromFontFile: out of memory")); FREE_IF(fce->mFontFileName); FREE_IF(fce->mFontType); FREE_IF(fce->mFamilyName); FREE_IF(fce->mStyleName); if (fce->mCCMap) FreeCCMap(fce->mCCMap); FREE_IF(fce); if (face) mFt2->DoneFace(face); FONT_SCAN_PRINTF(("\n")); return nsnull; } nsFontCatalogEntry * nsFT2FontCatalog::NewFceFromSummary(nsNameValuePairDB *aDB) { const char *type, *name, *value; PRBool rslt; nsFontCatalogEntry *fce = nsnull; long longVal; unsigned long uLongVal; int num, intVal, i; nsCompressedCharMap ccmapObj; fce = (nsFontCatalogEntry *)calloc(1, sizeof(nsFontCatalogEntry)); if (!fce) goto cleanup_and_return; if (!aDB->GetNextGroup(&type, "Font_", 5)) { FONT_CATALOG_PRINTF(("file garbled: expected begin=Font_, got %s", type)); goto cleanup_and_return; } while (aDB->GetNextElement(&name, &value) > 0) { if (STRMATCH(name,"FamilyName")) { if (fce->mFamilyName) { FONT_CATALOG_PRINTF(("family name defined multiple times (%s, %s)", fce->mFamilyName, value)); goto cleanup_and_return; } fce->mFamilyName = strdup(value); if (!fce->mFamilyName) goto cleanup_and_return; } else if (STRMATCH(name,"Flags")) { if (fce->mFlags != 0) { FONT_CATALOG_PRINTF(("Flags defined multiple times (%s)", fce->mFontFileName?fce->mFontFileName:"")); goto cleanup_and_return; } num = sscanf(value, "%lx", &uLongVal); if (num != 1) { FONT_CATALOG_PRINTF(("failed to parse Flags (%s)",value)); goto cleanup_and_return; } fce->mFlags = uLongVal; if (fce->mFlags & FCE_FLAGS_SURROGATE) { ccmapObj.Extend(); } } else if (STRMATCH(name,"FontFileName")) { if (fce->mFontFileName) { FONT_CATALOG_PRINTF(("font filename defined multiple times (%s, %s)", fce->mFontFileName, value)); goto cleanup_and_return; } fce->mFontFileName = strdup(value); if (!fce->mFontFileName) goto cleanup_and_return; } else if (STRMATCH(name,"MTime")) { if (fce->mMTime != 0) { FONT_CATALOG_PRINTF(("time defined multiple times (%s)", fce->mFontFileName?fce->mFontFileName:"")); goto cleanup_and_return; } num = sscanf(value, "%lu", &uLongVal); if ((num != 1) || (uLongVal==0)) { FONT_CATALOG_PRINTF(("failed to parse time (%s)",value)); goto cleanup_and_return; } fce->mMTime = uLongVal; } else if (STRMATCH(name,"FontType")) { if (fce->mFontType) { FONT_CATALOG_PRINTF(("font type defined multiple times (%s, %s)", fce->mFontType, value)); goto cleanup_and_return; } fce->mFontType = strdup(value); if (!fce->mFontType) goto cleanup_and_return; } else if (STRMATCH(name,"FaceIndex")) { if (fce->mFaceIndex != 0) { FONT_CATALOG_PRINTF(("face index defined multiple times (%d, %s)", fce->mFaceIndex, value)); goto cleanup_and_return; } longVal = atol(value); if (longVal<0) { FONT_CATALOG_PRINTF(("failed to parse face index (%s)",value)); goto cleanup_and_return; } fce->mFaceIndex = longVal; } else if (STRMATCH(name,"NumFaces")) { if (fce->mNumFaces != 0) { FONT_CATALOG_PRINTF(("num faces defined multiple times (%d, %s)", fce->mNumFaces, value)); goto cleanup_and_return; } intVal = atoi(value); if (intVal<0) { FONT_CATALOG_PRINTF(("failed to parse num faces (%s)",value)); goto cleanup_and_return; } fce->mNumFaces = intVal; } else if (STRMATCH(name,"StyleName")) { if (fce->mStyleName != 0) { FONT_CATALOG_PRINTF(("font style defined multiple times (%s, %s)", fce->mStyleName, value)); goto cleanup_and_return; } fce->mStyleName = strdup(value); if (!fce->mStyleName) goto cleanup_and_return; } else if (STRMATCH(name,"NumGlyphs")) { if (fce->mNumGlyphs != 0) { FONT_CATALOG_PRINTF(("num glyphs defined multiple times (%d, %s)", fce->mNumGlyphs, value)); goto cleanup_and_return; } intVal = atoi(value); if (intVal<0) { FONT_CATALOG_PRINTF(("failed to parse num glyphs (%s)",value)); goto cleanup_and_return; } fce->mNumGlyphs = intVal; } else if (STRMATCH(name,"NumUsableGlyphs")) { if (fce->mNumUsableGlyphs != 0) { FONT_CATALOG_PRINTF(("num usable glyphs defined multiple times (%d, %s)", fce->mNumUsableGlyphs, value)); goto cleanup_and_return; } intVal = atoi(value); if (intVal<0) { FONT_CATALOG_PRINTF(("failed to parse num usable glyphs (%s)",value)); goto cleanup_and_return; } fce->mNumUsableGlyphs = intVal; } else if (STRMATCH(name,"FaceFlags")) { if (fce->mFaceFlags != 0) { FONT_CATALOG_PRINTF(("face flags defined multiple times (0x%lx, %s)", fce->mFaceFlags, value)); goto cleanup_and_return; } num = sscanf(value, "%lx", &uLongVal); if (num != 1) { FONT_CATALOG_PRINTF(("failed to parse face flags (%s)",value)); goto cleanup_and_return; } fce->mFaceFlags = uLongVal; } else if (STRMATCH(name,"StyleFlags")) { if (fce->mStyleFlags != 0) { FONT_CATALOG_PRINTF(("style flags defined multiple times (0x%lx, %s)", fce->mStyleFlags, value)); goto cleanup_and_return; } num = sscanf(value, "%lx", &uLongVal); if (num != 1) { FONT_CATALOG_PRINTF(("failed to parse style flags (%s)",value)); goto cleanup_and_return; } fce->mStyleFlags = uLongVal; } else if (STRMATCH(name,"Weight")) { if (fce->mWeight != 0) { FONT_CATALOG_PRINTF(("weight defined multiple times (0x%d, %s)", fce->mWeight, value)); goto cleanup_and_return; } intVal = atoi(value); if ((intVal<0) || (intVal>950)) { FONT_CATALOG_PRINTF(("failed to parse weight (%s)",value)); goto cleanup_and_return; } fce->mWeight = (unsigned short)intVal; } else if (STRMATCH(name,"Width")) { if (fce->mWidth != 0) { FONT_CATALOG_PRINTF(("width defined multiple times (0x%d, %s)", fce->mWeight, value)); goto cleanup_and_return; } intVal = atoi(value); if ((intVal<0) || (intVal>9)) { FONT_CATALOG_PRINTF(("failed to parse (or invalid) width (%s)",value)); goto cleanup_and_return; } fce->mWidth = (unsigned short)intVal; } else if (STRMATCH(name,"CodePageRange1")) { if (fce->mCodePageRange1 != 0) { FONT_CATALOG_PRINTF(("CodePageRange1 defined multiple times (0x%lx, %s)", fce->mCodePageRange1, value)); goto cleanup_and_return; } num = sscanf(value, "%lx", &uLongVal); if (num != 1) { FONT_CATALOG_PRINTF(("failed to parse mCodePageRange1 (%s)",value)); goto cleanup_and_return; } fce->mCodePageRange1 = uLongVal; } else if (STRMATCH(name,"CodePageRange2")) { if (fce->mCodePageRange2 != 0) { FONT_CATALOG_PRINTF(("CodePageRange2 defined multiple times (0x%lx, %s)", fce->mCodePageRange2, value)); goto cleanup_and_return; } num = sscanf(value, "%lx", &uLongVal); if (num != 1) { FONT_CATALOG_PRINTF(("failed to parse mCodePageRange2 (%s)",value)); goto cleanup_and_return; } fce->mCodePageRange2 = uLongVal; } else if (STRMATCH(name,"VendorID")) { if (fce->mVendorID[0] != '\0') { FONT_CATALOG_PRINTF(("vendor id defined multiple times (%s, %s)", fce->mVendorID, value)); goto cleanup_and_return; } memset((char*)fce->mVendorID, 0, sizeof(fce->mVendorID)); strncpy((char*)fce->mVendorID, value, sizeof(fce->mVendorID)-1); } else if (STRMATCH(name,"EmbeddedBitmapHeights")) { if (fce->mNumEmbeddedBitmaps != 0) { FONT_CATALOG_PRINTF(("EmbeddedBitmapHeights defined multiple times")); goto cleanup_and_return; } int embeddedBitmapHeights[1024]; int maxEmbeddedBitmaps = sizeof(embeddedBitmapHeights)/sizeof(embeddedBitmapHeights[0]); int numEmbeddedBitmaps = 0; const char *p = value; const char *q; while ((q=strchr(p, ','))) { intVal = atoi(p); if (intVal < 1) { FONT_CATALOG_PRINTF(("failed to parse EmbeddedBitmapHeights(%s)",value)); goto cleanup_and_return; } embeddedBitmapHeights[numEmbeddedBitmaps++] = intVal; if (numEmbeddedBitmaps >= maxEmbeddedBitmaps) { FONT_CATALOG_PRINTF(("can only handle %d numEmbeddedBitmaps", maxEmbeddedBitmaps)); break; } p = q + 1; // point to next height } fce->mNumEmbeddedBitmaps = numEmbeddedBitmaps; if (fce->mNumEmbeddedBitmaps) { fce->mEmbeddedBitmapHeights = (int*)calloc(fce->mNumEmbeddedBitmaps, sizeof(int)); if (!fce->mEmbeddedBitmapHeights) goto cleanup_and_return; for (int i=0; imNumEmbeddedBitmaps; i++) fce->mEmbeddedBitmapHeights[i] = embeddedBitmapHeights[i]; } } else if (STRNMATCH(name,"CCMap:",6)) { num = sscanf(name+6, "%lx", &uLongVal); if (num != 1) { FONT_CATALOG_PRINTF(("failed to parse CCMap address (%s)",name+6)); goto cleanup_and_return; } rslt = ParseCCMapLine(&ccmapObj, uLongVal, value); if (!rslt) { FONT_CATALOG_PRINTF(("failed to parse CCMap value (%s)",value)); goto cleanup_and_return; } } } fce->mCCMap = ccmapObj.NewCCMap(); if (!fce->mCCMap) { FONT_CATALOG_PRINTF(("missing char map")); goto cleanup_and_return; } if (!fce->mFamilyName) { FONT_CATALOG_PRINTF(("missing family name")); goto cleanup_and_return; } if ((fce->mFlags&FCE_FLAGS_ISVALID) && (fce->mFlags == 0)) { FONT_CATALOG_PRINTF(("missing flags")); goto cleanup_and_return; } if (!fce->mFontFileName) { FONT_CATALOG_PRINTF(("missing font file name")); goto cleanup_and_return; } if (fce->mMTime == 0) { FONT_CATALOG_PRINTF(("missing mtime")); goto cleanup_and_return; } if (!fce->mFontType) { FONT_CATALOG_PRINTF(("missing font type")); goto cleanup_and_return; } if (!fce->mStyleName) { FONT_CATALOG_PRINTF(("missing style name")); goto cleanup_and_return; } if ((fce->mFlags&FCE_FLAGS_ISVALID) && (fce->mNumGlyphs == 0)) { FONT_CATALOG_PRINTF(("missing num glyphs")); goto cleanup_and_return; } if (fce->mFlags&FCE_FLAGS_ISVALID && ((fce->mFlags & FCE_FLAGS_UNICODE) || (fce->mFlags & FCE_FLAGS_SURROGATE)) && (fce->mNumUsableGlyphs == 0)) { FONT_CATALOG_PRINTF(("missing num usable glyphs")); goto cleanup_and_return; } return fce; cleanup_and_return: FONT_CATALOG_PRINTF(("nsFT2FontCatalog::NewFceFromSummary failed")); if (fce->mCCMap) FreeCCMap(fce->mCCMap); FREE_IF(fce->mFamilyName); FREE_IF(fce->mFontFileName); FREE_IF(fce->mFontType); FREE_IF(fce->mStyleName); FREE_IF(fce->mEmbeddedBitmapHeights); FREE_IF(fce); return nsnull; } nsFontCatalog * nsFT2FontCatalog::NewFontCatalog() { nsFontCatalog *fc; fc = (nsFontCatalog *)calloc(1, sizeof(nsFontCatalog)); return fc; } PRBool nsFT2FontCatalog::ParseCCMapLine(nsCompressedCharMap *aCCMapObj, long base, const char *valString) { int i, j, len; unsigned int byte; PRUint32 pagechar = (PRUint32)base; // check we have the right number of chars len = strlen(valString); if (len != (2*(CCMAP_BITS_PER_PAGE/8))) return PR_FALSE; const char *p = valString; for (i=0; i<(CCMAP_BITS_PER_PAGE/8); i++) { #if 0 // scanf is way too slow int num = sscanf(valString+(2*i), "%2x", &byte); if (num != 1) return PR_FALSE; #else NS_ASSERTION((*p>='0' && *p<='9') || (*p>='a' && *p<='f') || (*p>='A' && *p<='F'), "Invalid ccmap char"); if (*p <= '9') byte = *p++ - '0'; else { byte = (*p++ & 0x4F) - 'A' + 10; } byte <<= 4; NS_ASSERTION((*p>='0' && *p<='9') || (*p>='a' && *p<='f') || (*p>='A' && *p<='F'), "Invalid ccmap char"); if (*p <= '9') byte |= *p++ - '0'; else { byte |= (*p++ & 0x4F) - 'A' + 10; } #endif if (byte == 0) { pagechar += 8; continue; } for (j=0; j<8; j++) { if (byte & (1<SetChar(pagechar); pagechar++; } } return PR_TRUE; } void nsFT2FontCatalog::PrintCCMap(nsNameValuePairDB *aDB, PRUint16 *aCCMap) { if (!aCCMap) return; PRUint32 page = CCMAP_BEGIN_AT_START_OF_MAP; while (NextNonEmptyCCMapPage(aCCMap, &page)) { //FONT_CATALOG_PRINTF(("page starting at 0x%04x has chars", page)); PrintPageBits(aDB, aCCMap, page); } } void nsFT2FontCatalog::PrintFontSummaries(nsNameValuePairDB *aDB, nsFontCatalog *aFontCatalog) { int i; nsFontCatalogEntry *fce; char font_num[30]; char buf[30]; aDB->PutStartGroup("FontSummariesInfo"); aDB->PutElement("", "#############################"); aDB->PutElement("", "# Font Summaries #"); aDB->PutElement("", "#############################"); aDB->PutElement("", "#"); sprintf(buf, "%d", aFontCatalog->numFonts); aDB->PutElement("NumFonts", buf); aDB->PutEndGroup("FontSummariesInfo"); for (i=0; inumFonts; i++) { fce = aFontCatalog->fonts[i]; sprintf(font_num, "Font_%d", i); aDB->PutStartGroup(font_num); aDB->PutElement("FamilyName", fce->mFamilyName); sprintf(buf, "%08x", fce->mFlags); aDB->PutElement("Flags", buf); aDB->PutElement("FontFileName", fce->mFontFileName); sprintf(buf, "%ld", fce->mMTime); aDB->PutElement("MTime", buf); aDB->PutElement("FontType", fce->mFontType); sprintf(buf, "%d", fce->mFaceIndex); aDB->PutElement("FaceIndex", buf); sprintf(buf, "%d", fce->mNumFaces); aDB->PutElement("NumFaces", buf); aDB->PutElement("StyleName", fce->mStyleName); sprintf(buf, "%d", fce->mNumGlyphs); aDB->PutElement("NumGlyphs", buf); sprintf(buf, "%d", fce->mNumUsableGlyphs); aDB->PutElement("NumUsableGlyphs", buf); sprintf(buf, "%08lx", fce->mFaceFlags); aDB->PutElement("FaceFlags", buf); sprintf(buf, "%08lx", fce->mStyleFlags); aDB->PutElement("StyleFlags", buf); sprintf(buf, "%d", fce->mWeight); aDB->PutElement("Weight", buf); sprintf(buf, "%d", fce->mWidth); aDB->PutElement("Width", buf); sprintf(buf, "%08lx", fce->mCodePageRange1); aDB->PutElement("CodePageRange1", buf); sprintf(buf, "%08lx", fce->mCodePageRange2); aDB->PutElement("CodePageRange2", buf); aDB->PutElement("VendorID", fce->mVendorID); nsCAutoString embeddedHeightStr(""); for (int j=0; jmNumEmbeddedBitmaps; j++) { sprintf(buf, "%d,", fce->mEmbeddedBitmapHeights[j]); embeddedHeightStr.Append(buf); } aDB->PutElement("EmbeddedBitmapHeights", PromiseFlatCString(embeddedHeightStr).get()); aDB->PutElement("", "# ccmap"); PrintCCMap(aDB, fce->mCCMap); aDB->PutEndGroup(font_num); } } void nsFT2FontCatalog::PrintFontSummaryVersion(nsNameValuePairDB *aDB) { char buf[30]; aDB->PutStartGroup(FONT_SUMMARY_VERSION_TAG); aDB->PutElement("", "#############################"); aDB->PutElement("", "# Font Summary Version #"); aDB->PutElement("", "#############################"); aDB->PutElement("", "#"); sprintf(buf, "%u.%u.%u", FONT_SUMMARY_VERSION_MAJOR, FONT_SUMMARY_VERSION_MINOR, FONT_SUMMARY_VERSION_REV); aDB->PutElement("Version", buf); aDB->PutEndGroup(FONT_SUMMARY_VERSION_TAG); } void nsFT2FontCatalog::PrintPageBits(nsNameValuePairDB *aDB, PRUint16 *aCCMap, PRUint32 aPageStart) { int i; PRUint32 pagechar = aPageStart; char addr[64]; char buf[64]; nsCAutoString ccmap_line(""); for (i=0; i<(CCMAP_BITS_PER_PAGE/8); i++) { unsigned char val = 0; for (int j=0; j<8; j++) { if (CCMAP_HAS_CHAR_EXT(aCCMap, pagechar)) { val |= 1 << j; } pagechar++; } sprintf(buf, "%02x", val); ccmap_line.Append(buf); } sprintf(addr, "CCMap:0x%04lx", (long)aPageStart); aDB->PutElement(addr, PromiseFlatCString(ccmap_line).get()); } PRBool nsFT2FontCatalog::ReadFontDirSummary(const nsACString& aFontSummaryFilename, nsHashtable* aFontFileNamesHash) { nsNameValuePairDB fc; int status; if (!fc.OpenForRead(aFontSummaryFilename)) { FONT_CATALOG_PRINTF(("could not open font catalog %s", PromiseFlatCString(aFontSummaryFilename).get())); return PR_FALSE; } // // check the font summary version number // status = CheckFontSummaryVersion(&fc); if (status != FC_FILE_OKAY) goto cleanup_and_return; // // read font summaries // ReadFontSummaries(aFontFileNamesHash, &fc); return PR_TRUE; cleanup_and_return: FONT_CATALOG_PRINTF(("nsFT2FontCatalog::ReadFontDirSummary failed")); return PR_FALSE; } int nsFT2FontCatalog::ReadFontSummaries(nsHashtable* aFontHash, nsNameValuePairDB *aDB) { const char *type, *name, *value; int i, numFonts = 0; nsFontCatalogEntry *fce = nsnull; // // Get the number of font summaries // if (!aDB->GetNextGroup(&type, "FontSummariesInfo")) { FONT_CATALOG_PRINTF(("file garbled: expected begin=FontSummariesInfo, " "got %s", type)); goto cleanup_and_return; } while (aDB->GetNextElement(&name, &value) > 0) { if (strcmp(name, "NumFonts")==0) { numFonts = atoi(value); if (numFonts<0) { FONT_CATALOG_PRINTF(("failed to parse num fonts (%s)", value)); goto cleanup_and_return; } } } for (i=0; imFontFileName); // Since we are hashing by file name we need to add a FaceIndex // else we would lose the other ttc faces if (fce->mFaceIndex != 0) { // add face num to hash key nsCAutoString key_str(fce->mFontFileName); char buf[20]; sprintf(buf, "/%d", fce->mFaceIndex); key_str.Append(buf); key = key_str; } FONT_CATALOG_PRINTF(("key = %s", key.GetString())); aFontHash->Put(&key, (void *)fce); } return numFonts; cleanup_and_return: FONT_CATALOG_PRINTF(("nsFT2FontCatalog::ReadFontSummaries failed")); return 0; } unsigned long nsFT2FontCatalog::GetRangeLanguage(const nsACString & aLanguage, PRInt16 aRange) { unsigned long *bit; if (aLanguage.IsEmpty()) return 0; nsCStringKey key(aLanguage); if (aRange == CPR1) bit = (unsigned long *)(mRange1Language->Get(&key)); if (aRange == CPR2) bit = (unsigned long *)(mRange2Language->Get(&key)); if (bit) return *bit; return 0; } nsFontVendorName sVendorNamesList[] = { { "2REB", "2Rebels" }, { "39BC", "Finley's Barcode Fonts" }, { "3ip", "Three Islands Press" }, { "918", "RavenType" }, { "ABC", "Altek Instruments" }, { "ACUT", "Acute Type" }, { "ADBE", "Adobe" }, { "AGFA", "Agfa Monotype" }, { "ALPH", "Alphameric Broadcast Solutions" }, { "ALTS", "Altsys (Macromedia)" }, { "AOP", "An Art of Penguin" }, { "APOS", "Apostrophic Laboratories" }, { "APPL", "Apple" }, { "ARPH", "Arphic Technology" }, { "ARS", "EN ARS" }, { "ATEC", "Page Technology Marketing" }, { "AZLS", "Azalea Software" }, { "B&H", "Bigelow & Holmes" }, { "BARS", "CIA (BAR CODES) UK" }, { "BERT", "Berthold" }, { "BITM", "Bitmap Software" }, { "BITS", "Bitstream" }, { "BLAH", "Mister Bla's Fontworx" }, { "BORW", "Borware" }, { "BOYB", "BoyBeaver Fonts" }, { "BRTC", "Bear Rock Technologies" }, { "BWFW", "B/W Fontworks" }, { "C21", "Club 21" }, { "CAK", "pluginfonts" }, { "CANO", "Canon" }, { "CASL", "H.W. Caslon" }, { "CDAC", "Centre for Development of Advanced Computing"}, { "CFA", "Computer Fonts Australia" }, { "CONR", "Connare" }, { "COOL", "Cool Fonts" }, { "CORD", "corduroy" }, { "CTDL", "China Type Designs" }, { "cwwf", "Computers World Wide/AC Capital Funding" }, { "DAMA", "Dalton Maag" }, { "DELV", "Delve Media Arts" }, { "DFS", "Datascan Font Service" }, { "DGL", "Digital Graphic Labs foundry" }, { "DS", "Dainippon Screen" }, { "DSCI", "Design Science" }, { "DSST", "Dubina Nikolay" }, { "DTC", "Digital Typeface" }, { "DTPS", "DTP-Software" }, { "dtpT", "dtpTypes" }, { "DUXB", "Duxbury Systems" }, { "DYNA", "DynaLab" }, { "EDGE", "Rivers Edge" }, { "EFF", "Electronic Font Foundry" }, { "EFNT", "E Fonts L.L.C." }, { "ELSE", "Elseware (Hewlett-Packard)" }, { "EMGR", "Emigre" }, { "EPSN", "Epson" }, { "ESIG", "E-Signature" }, { "EVER", "Everson Typography" }, { "FBI", "The Font Bureau" }, { "FCAB", "The Font Cabinet" }, { "FCAN", "fontage canada" }, { "FNTF", "Fontfoundry" }, { "FONT", "Font Source" }, { "FS", "Formula Solutions" }, { "FSE", "Font Source Europe" }, { "FSI", "FSI Fonts und Software" }, { "FTFT", "FontFont" }, { "FWRE", "Fontware" }, { "GALA", "Galápagos Design Group" }, { "GD", "GD Fonts" }, { "GF", "GarageFonts" }, { "GLYF", "Glyph Systems" }, { "GOAT", "Dingbat Dungeon" }, { "GOGO", "Fonts-A-Go-Go" }, { "GPI", "Gamma Productions" }, { "GRIL", "Grilled cheese" }, { "HILL", "Hill Systems" }, { "HL", "High-Logic" }, { "HOUS", "House Industries" }, { "HP", "Hewlett-Packard" }, { "HS", "HermesSOFT" }, { "HY", "HanYang System" }, { "IBM", "IBM" }, { "IDAU", "IDAutomation" }, { "IDEE", "IDEE TYPOGRAFICA" }, { "IDF", "International Digital Fonts" }, { "ILP", "Indigenous Language Project" }, { "IMPR", "Impress" }, { "INVC", "Invoice Central" }, { "ITF", "International TypeFounders" }, { "KATF", "Kingsley/ATF" }, { "KUBA", "Kuba Tatarkiewicz" }, { "LARA", "Larabiefonts" }, { "LEAF", "Interleaf" }, { "LETR", "Letraset" }, { "LGX", "Logix Research Institute" }, { "LING", "Linguist's Software" }, { "LINO", "Linotype" }, { "LP", "LetterPerfect Fonts" }, { "LTRX", "Lighttracks" }, { "MACR", "Macromedia" }, { "MATS", "Match Fonts" }, { "MC", "Cerajewski Computer Consulting" }, { "MEIR", "Meir Sadan" }, { "MF", "Magic Fonts" }, { "MFNT", "Masterfont" }, { "MILL", "Millan" }, { "MJ", "Majus" }, { "MJR", "Majur" }, { "MLGC", "Micrologic Software" }, { "MONO", "Agfa Monotype" }, { "MOON", "Moonlight Type and Technolog" }, { "MS", "Microsoft" }, { "MSCR", "Majus" }, { "MSE", "MSE-iT" }, { "MT", "Agfa Monotype" }, { "MTY", "Motoya" }, { "MUTF", "Murasu Systems Sdn. Bhd" }, { "MYFO", "MyFonts" }, { "NB", "No Bodoni Typography" }, { "NDTC", "Neufville Digital" }, { "NEC", "NEC" }, { "NIS", "NIS" }, { "ORBI", "Orbit Enterprises" }, { "P22", "P22" }, { "PARA", "ParaType" }, { "PDWX", "Parsons Design Workx" }, { "PF", "Phil's Fonts" }, { "PLAT", "PLATINUM technology" }, { "PRFS", "Production First Software" }, { "PSY", "PSY/OPS" }, { "PTF", "Porchez Typofonderie" }, { "PTMI", "Page Technology Marketing" }, { "PYRS", "Pyrus" }, { "QMSI", "QMS/Imagen" }, { "RKFN", "R K Fonts" }, { "robo", "Buro Petr van Blokland" }, { "RRT", "Red Rooster Typefounders" }, { "RUDY", "RudynFluffy" }, { "RYOB", "Ryobi" }, { "SAX", "s.a.x. Software" }, { "Sean", "The FontSite" }, { "SFUN", "Software Union" }, { "SG", "Scooter Graphics" }, { "SHFT", "Shift" }, { "SIG", "Signature Software" }, { "SIL", "SIL International" }, { "SIT", "Summit Information Technologies" }, { "skz", "Celtic Lady's Fonts" }, { "SN", "SourceNet" }, { "SOHO", "Soft Horizons" }, { "SOS", "Standing Ovations Software" }, { "STF", "Brian Sooy + Sooy Type Foundry" }, { "SUNW", "sunwalk fontworks" }, { "SWFT", "Swfte International" }, { "SYN", "SynFonts" }, { "SYRC", "Syriac Computing Institute" }, { "TDR", "Tansin A. Darcos" }, { "TERM", "Terminal Design" }, { "TF", "Treacyfaces / Headliners" }, { "TILD", "Tilde, SIA" }, { "TIRO", "Tiro Typeworks" }, { "TMF", "The MicroFoundry" }, { "TPTC", "Test Pilot Collective" }, { "TR", "Type Revivals" }, { "TS", "TamilSoft" }, { "TTG", "Twardoch Typography" }, { "TYPE", "TypeGroup" }, { "TYPO", "Typodermic" }, { "UA", "UnAuthorized Type" }, { "UNKN", "Unknown Vendor" }, { "URW", "URW++" }, { "UT", "Unitype" }, { "VKP", "Vijay K. Patel" }, { "VLKF", "Visualogik Technology & Design" }, { "VOG", "Martin Vogel" }, { "VROM", "Vladimir Romanov" }, { "VT", "VISUALTYPE SRL" }, { "WASP", "Wasp barcode" }, { "WM", "Webmakers India" }, { "XFC", "Xerox Font Services" }, { "Y&Y", "Y&Y" }, { "ZeGr", "Zebra Font Factory" }, { "zeta", "Tangram Studio" }, { "ZSFT", "Zsoft" }, { nsnull, nsnull }, }; // TODO: what TT_OS2_CPR1_OEM standard for. use "oem" temporarily. nsulCodePageRangeLanguage ulCodePageRange1Language[] = { { TT_OS2_CPR1_LATIN1 | TT_OS2_CPR1_MAC_ROMAN, "x-western" }, { TT_OS2_CPR1_LATIN2, "x-central-euro" }, { TT_OS2_CPR1_CYRILLIC, "x-cyrillic" }, { TT_OS2_CPR1_GREEK, "el" }, { TT_OS2_CPR1_TURKISH, "tr" }, { TT_OS2_CPR1_HEBREW, "he" }, { TT_OS2_CPR1_ARABIC, "ar" }, { TT_OS2_CPR1_BALTIC, "x-baltic" }, { TT_OS2_CPR1_VIETNAMESE, "vietnamese" }, { TT_OS2_CPR1_THAI, "th" }, { TT_OS2_CPR1_JAPANESE, "ja" }, { TT_OS2_CPR1_CHINESE_SIMP, "zh-cn" }, { TT_OS2_CPR1_KO_WANSUNG | TT_OS2_CPR1_KO_JOHAB, "ko" }, { TT_OS2_CPR1_CHINESE_TRAD, "zh-tw" }, { TT_OS2_CPR1_OEM, "oem" }, { TT_OS2_CPR1_SYMBOL, "symbol" }, { 0, nsnull }, }; nsulCodePageRangeLanguage ulCodePageRange2Language[] = { { TT_OS2_CPR2_GREEK | TT_OS2_CPR2_GREEK_437G, "el" }, { TT_OS2_CPR2_RUSSIAN, "x-cyrillic" }, { TT_OS2_CPR2_NORDIC, "x-western" }, { TT_OS2_CPR2_ARABIC | TT_OS2_CPR2_ARABIC_708, "ar" }, { TT_OS2_CPR2_CA_FRENCH, "x-western" }, { TT_OS2_CPR2_HEBREW, "he" }, { TT_OS2_CPR2_ICELANDIC, "icelandic" }, { TT_OS2_CPR2_PORTUGESE, "x-western" }, { TT_OS2_CPR2_TURKISH, "tr" }, { TT_OS2_CPR2_CYRILLIC, "x-cyrillic" }, { TT_OS2_CPR2_LATIN2, "x-central-euro" }, { TT_OS2_CPR2_BALTIC, "x-baltic" }, { TT_OS2_CPR2_WE_LATIN1 || TT_OS2_CPR2_US, "x-western" }, { 0, nsnull }, }; #endif /* #if (!defined(MOZ_ENABLE_FREETYPE2)) */