patch = Andrew Schultz(ajschult@eos.ncsu.edu) r = louie sr = bryner git-svn-id: svn://10.0.0.236/trunk@140683 18797224-902f-48f8-a5cc-f745e15eee43
2478 lines
82 KiB
C++
2478 lines
82 KiB
C++
/* -*- 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 <bstell@netscape.com>
|
||
*
|
||
*
|
||
* 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 "nsFT2FontCatalog.h"
|
||
#include "nsFontDebug.h"
|
||
|
||
PRUint32 gFontDebug = 0 | NS_FONT_DEBUG_FONT_SCAN;
|
||
|
||
#if (defined(MOZ_ENABLE_FREETYPE2))
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/time.h>
|
||
#include <dirent.h>
|
||
#include "nsAppDirectoryServiceDefs.h"
|
||
#include "nsLocalFileUnix.h"
|
||
#include "nsIEnumerator.h"
|
||
#include "nsITimelineService.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 <ft2build.h>
|
||
#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[];
|
||
|
||
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
|
||
static NS_DEFINE_CID(kCharSetManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
|
||
|
||
nsHashtable* nsFT2FontCatalog::sVendorNames = nsnull;
|
||
nsIPref* nsFT2FontCatalog::sPref = nsnull;
|
||
|
||
#endif
|
||
|
||
//
|
||
// Implementation of Interfaces nsIFontCatalogService
|
||
//
|
||
NS_IMPL_ISUPPORTS1(nsFT2FontCatalog, nsIFontCatalogService)
|
||
|
||
nsFT2FontCatalog::nsFT2FontCatalog()
|
||
{
|
||
#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,
|
||
nsISupportsArray **_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<nsITrueTypeFontCatalogEntry> aFce;
|
||
nsCOMPtr<nsISupports> genericFce;
|
||
nsCOMPtr<nsISupportsArray> entries;
|
||
NS_NewISupportsArray(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);
|
||
}
|
||
|
||
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; i<fce->mNumFaces; 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; i<fc->numFonts; 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; i<fce->mNumEmbeddedBitmaps; i++)
|
||
printf("%d,", fce->mEmbeddedBitmapHeights[i]);
|
||
printf("\n");
|
||
printCCMap(fce->mCCMap);
|
||
}
|
||
#endif
|
||
|
||
void
|
||
nsFT2FontCatalog::FixUpFontCatalog(nsFontCatalog *fc)
|
||
{
|
||
int i;
|
||
for (i=0; i<fc->numFonts; 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 = "<unknown>";
|
||
}
|
||
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; i<fc->numFonts; i++) {
|
||
nsFontCatalogEntry *fce;
|
||
fce = fc->fonts[i];
|
||
FreeFontCatalogEntry(fce);
|
||
}
|
||
free(fc->fonts);
|
||
free(fc);
|
||
}
|
||
|
||
void
|
||
nsFT2FontCatalog::FreeDirCatalog(nsDirCatalog *dc)
|
||
{
|
||
int i;
|
||
for (i=0; i<dc->numDirs; 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<nsIFile> 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; i<aOldDirCatalog->numDirs; 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; i<mFontCatalog->numFonts; 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<nsILocalFile> 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<nsILocalFile> 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 =
|
||
// <last part of the path>.d<device number>.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 = "<unknown>";
|
||
}
|
||
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<nsIFile> dir;
|
||
nsCOMPtr<nsILocalFile> dirLocal;
|
||
nsCOMPtr<nsILocalFile> dirEntry;
|
||
nsCOMPtr<nsISimpleEnumerator> 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()
|
||
:"<none>"));
|
||
|
||
//
|
||
// 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; i<dirFontCatalog->numFonts; 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; j<num_faces; j++) {
|
||
fce = NewFceFromFontFile(aFreeTypeLibrary, aFontFileName,
|
||
j, nsnull);
|
||
if (!fce) {
|
||
//FONT_CATALOG_PRINTF(("failed to catalog %s/%d\n", aFontFileName, j));
|
||
return;
|
||
}
|
||
AddFont(aFontCatalog, fce);
|
||
}
|
||
}
|
||
|
||
PRBool
|
||
nsFT2FontCatalog::InitGlobals(FT_Library lib)
|
||
{
|
||
nsDirCatalog *dirCatalog = nsnull;
|
||
nsCAutoString prefix("font.directory.truetype.");
|
||
#ifdef DEBUG
|
||
int dump_catalog = 0;
|
||
int num_ftfonts = 0;
|
||
int i;
|
||
#endif
|
||
nsFontVendorName *vn = sVendorNamesList;
|
||
|
||
nsulCodePageRangeLanguage *crl = nsnull;
|
||
|
||
nsServiceManager::GetService(NS_PREF_CONTRACTID,
|
||
NS_GET_IID(nsIPref),
|
||
(nsISupports**) &sPref);
|
||
if (!sPref)
|
||
goto cleanup_and_return;
|
||
|
||
mFontCatalog = NewFontCatalog();
|
||
if (!mFontCatalog)
|
||
goto cleanup_and_return;
|
||
|
||
sVendorNames = new nsHashtable();
|
||
if (!sVendorNames)
|
||
goto cleanup_and_return;
|
||
while (vn->vendorID) {
|
||
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; i<mFontCatalog->numFonts; 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; i<fce->mNumEmbeddedBitmaps; 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<nsICharRepresentable> 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; i<fce->mNumEmbeddedBitmaps; 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<<j))
|
||
aCCMapObj->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; i<aFontCatalog->numFonts; 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; j<fce->mNumEmbeddedBitmaps; 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; i<numFonts; i++) {
|
||
fce = NewFceFromSummary(aDB);
|
||
if (!fce)
|
||
goto cleanup_and_return;
|
||
nsCStringKey key(fce->mFontFileName);
|
||
// 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<EFBFBD>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)) */
|