Mozilla/mozilla/gfx/src/x11shared/nsFT2FontCatalog.cpp
louie.zhao%sun.com 47895531db bug 166833 "nsFT2FontCatalog leaks memory"
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
2003-04-04 07:05:56 +00:00

2478 lines
82 KiB
C++
Raw Blame History

/* -*- 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)) */