629 lines
18 KiB
C++
629 lines
18 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla 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/MPL/
|
|
*
|
|
* 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) 1999
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Frank Yung-Fong Tang <ftang@netscape.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of 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 MPL, 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 MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "nsMacUnicodeFontInfo.h"
|
|
#include "nsCRT.h"
|
|
#include "prmem.h"
|
|
#include <Fonts.h>
|
|
|
|
//#define DEBUG_TRUE_TYPE
|
|
#include "nsICharRepresentable.h"
|
|
#include "nsCompressedCharMap.h"
|
|
#include "nsIObserver.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsDependentString.h"
|
|
#include "nsLiteralString.h"
|
|
#include "nsDeviceContextMac.h"
|
|
#include "nsICharsetConverterManager.h"
|
|
#include "nsIPersistentProperties2.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsHashtable.h"
|
|
#include <ATSTypes.h>
|
|
#include <SFNTTypes.h>
|
|
#include <SFNTLayoutTypes.h>
|
|
|
|
//#define TRACK_INIT_PERFORMANCE
|
|
|
|
#ifdef TRACK_INIT_PERFORMANCE
|
|
#include <DriverServices.h>
|
|
#endif
|
|
|
|
class nsFontCleanupObserver : public nsIObserver {
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
nsFontCleanupObserver() { }
|
|
virtual ~nsFontCleanupObserver() {}
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS1(nsFontCleanupObserver, nsIObserver)
|
|
|
|
NS_IMETHODIMP nsFontCleanupObserver::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
|
|
{
|
|
if (! nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID,aTopic))
|
|
{
|
|
nsMacUnicodeFontInfo::FreeGlobals();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
|
|
|
|
static nsIPersistentProperties* gFontEncodingProperties = nsnull;
|
|
static nsICharsetConverterManager* gCharsetManager = nsnull;
|
|
static nsObjectHashtable* gFontMaps = nsnull;
|
|
static nsFontCleanupObserver *gFontCleanupObserver = nsnull;
|
|
static PRUint16* gCCMap = nsnull;
|
|
|
|
|
|
#ifdef IS_BIG_ENDIAN
|
|
# undef GET_SHORT
|
|
# define GET_SHORT(p) (*((PRUint16*)p))
|
|
# undef GET_LONG
|
|
# define GET_LONG(p) (*((PRUint32*)p))
|
|
#else
|
|
# ifdef IS_LITTLE_ENDIAN
|
|
# undef GET_SHORT
|
|
# define GET_SHORT(p) (((p)[0] << 8) | (p)[1])
|
|
# undef GET_LONG
|
|
# define GET_LONG(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3])
|
|
# endif
|
|
#endif
|
|
|
|
// The following should be defined in ATSTypes.h, but they ar not
|
|
enum {
|
|
kFMOpenTypeFontTechnology = FOUR_CHAR_CODE('OTTO')
|
|
};
|
|
|
|
// The following should be defined in SNFTTypes.h, but they ar not
|
|
enum {
|
|
headFontTableTag = FOUR_CHAR_CODE('head'),
|
|
locaFontTableTag = FOUR_CHAR_CODE('loca')
|
|
};
|
|
|
|
#define ADD_GLYPH(a,b) SET_REPRESENTABLE(a,b)
|
|
#define FONT_HAS_GLYPH(a,b) IS_REPRESENTABLE(a,b)
|
|
|
|
#undef SET_SPACE
|
|
#define SET_SPACE(c) ADD_GLYPH(spaces, c)
|
|
#undef SHOULD_BE_SPACE
|
|
#define SHOULD_BE_SPACE(c) FONT_HAS_GLYPH(spaces, c)
|
|
|
|
static PRInt8
|
|
GetIndexToLocFormat(FMFont aFont)
|
|
{
|
|
PRUint16 indexToLocFormat;
|
|
ByteCount len = 0;
|
|
OSStatus err = ::FMGetFontTable(aFont, headFontTableTag, 50, 2, &indexToLocFormat, nsnull);
|
|
if (err != noErr)
|
|
return -1;
|
|
|
|
if (!indexToLocFormat)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static PRUint8*
|
|
GetSpaces(FMFont aFont, PRUint32* aMaxGlyph)
|
|
{
|
|
PRInt8 isLong = GetIndexToLocFormat(aFont);
|
|
if (isLong < 0)
|
|
return nsnull;
|
|
|
|
ByteCount len = 0;
|
|
OSStatus err = ::FMGetFontTable(aFont, locaFontTableTag, 0, 0, NULL, &len);
|
|
|
|
if ((err != noErr) || (!len))
|
|
return nsnull;
|
|
|
|
PRUint8* buf = (PRUint8*) nsMemory::Alloc(len);
|
|
NS_ASSERTION(buf, "cannot read 'loca' table because out of memory");
|
|
if (!buf)
|
|
return nsnull;
|
|
|
|
ByteCount newLen = 0;
|
|
err = ::FMGetFontTable(aFont, locaFontTableTag, 0, len, buf, &newLen);
|
|
NS_ASSERTION((newLen == len), "cannot read 'loca' table from the font");
|
|
|
|
if (newLen != len)
|
|
{
|
|
nsMemory::Free(buf);
|
|
return nsnull;
|
|
}
|
|
|
|
if (isLong)
|
|
{
|
|
PRUint32 longLen = ((len / 4) - 1);
|
|
*aMaxGlyph = longLen;
|
|
PRUint32* longBuf = (PRUint32*) buf;
|
|
for (PRUint32 i = 0; i < longLen; i++)
|
|
{
|
|
if (longBuf[i] == longBuf[i+1])
|
|
buf[i] = 1;
|
|
else
|
|
buf[i] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PRUint32 shortLen = ((len / 2) - 1);
|
|
*aMaxGlyph = shortLen;
|
|
PRUint16* shortBuf = (PRUint16*) buf;
|
|
for (PRUint16 i = 0; i < shortLen; i++)
|
|
{
|
|
if (shortBuf[i] == shortBuf[i+1])
|
|
buf[i] = 1;
|
|
else
|
|
buf[i] = 0;
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
static int spacesInitialized = 0;
|
|
static PRUint32 spaces[2048];
|
|
static void InitSpace()
|
|
{
|
|
if (!spacesInitialized)
|
|
{
|
|
spacesInitialized = 1;
|
|
SET_SPACE(0x0020);
|
|
SET_SPACE(0x00A0);
|
|
for (PRUint16 c = 0x2000; c <= 0x200B; c++)
|
|
SET_SPACE(c);
|
|
SET_SPACE(0x3000);
|
|
}
|
|
}
|
|
|
|
static void HandleFormat4(PRUint16* aEntry, PRUint8* aEnd,
|
|
PRUint8* aIsSpace, PRUint32 aMaxGlyph,
|
|
PRUint32* aFontInfo)
|
|
{
|
|
// notice aIsSpace could be nsnull in case of OpenType font
|
|
PRUint8* end = aEnd;
|
|
PRUint16* s = aEntry;
|
|
PRUint16 segCount = s[3] / 2;
|
|
PRUint16* endCode = &s[7];
|
|
PRUint16* startCode = endCode + segCount + 1;
|
|
PRUint16* idDelta = startCode + segCount;
|
|
PRUint16* idRangeOffset = idDelta + segCount;
|
|
PRUint16* glyphIdArray = idRangeOffset + segCount;
|
|
|
|
PRUint16 i;
|
|
InitSpace();
|
|
|
|
for (i = 0; i < segCount; i++)
|
|
{
|
|
if (idRangeOffset[i])
|
|
{
|
|
PRUint16 startC = startCode[i];
|
|
PRUint16 endC = endCode[i];
|
|
for (PRUint32 c = startC; c <= endC; c++)
|
|
{
|
|
PRUint16* g = (idRangeOffset[i]/2 + (c - startC) + &idRangeOffset[i]);
|
|
if ((PRUint8*) g < end)
|
|
{
|
|
if (*g)
|
|
{
|
|
PRUint16 glyph = idDelta[i] + *g;
|
|
if (glyph < aMaxGlyph)
|
|
{
|
|
if (aIsSpace && aIsSpace[glyph])
|
|
{
|
|
if (SHOULD_BE_SPACE(c))
|
|
ADD_GLYPH(aFontInfo, c);
|
|
}
|
|
else
|
|
{
|
|
ADD_GLYPH(aFontInfo, c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// XXX should we trust this font at all if it does this?
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PRUint16 endC = endCode[i];
|
|
for (PRUint32 c = startCode[i]; c <= endC; c++)
|
|
{
|
|
PRUint16 glyph = idDelta[i] + c;
|
|
if (glyph < aMaxGlyph)
|
|
{
|
|
if (aIsSpace && aIsSpace[glyph])
|
|
{
|
|
if (SHOULD_BE_SPACE(c))
|
|
ADD_GLYPH(aFontInfo, c);
|
|
}
|
|
else
|
|
{
|
|
ADD_GLYPH(aFontInfo, c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static PRBool FillFontInfoFromCMAP(FMFont aFont, PRUint32 *aFontInfo, FourCharCode aFontFormat)
|
|
{
|
|
ByteCount len;
|
|
OSErr err = ::FMGetFontTable(aFont, cmapFontTableTag, 0, 0, NULL, &len);
|
|
if((err!=noErr) || (!len))
|
|
return PR_FALSE;
|
|
|
|
PRUint8* buf = (PRUint8*) nsMemory::Alloc(len);
|
|
NS_ASSERTION(buf, "cannot read cmap because out of memory");
|
|
if (!buf)
|
|
return PR_FALSE;
|
|
|
|
ByteCount newLen;
|
|
err = ::FMGetFontTable(aFont, cmapFontTableTag, 0, len, buf, &newLen);
|
|
NS_ASSERTION(newLen == len, "cannot read cmap from the font");
|
|
if (newLen != len)
|
|
{
|
|
nsMemory::Free(buf);
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRUint8* p = buf + sizeof(PRUint16); // skip version, move to numberSubtables
|
|
PRUint16 n = GET_SHORT(p); // get numberSubtables
|
|
p += sizeof(PRUint16); // skip numberSubtables, move to the encoding subtables
|
|
|
|
PRUint16 i;
|
|
PRUint32 offset;
|
|
PRUint32 platformUnicodeOffset = 0;
|
|
// we look for platform =3 and encoding =1,
|
|
// if we cannot find it but there are a platform = 0 there, we
|
|
// remmeber that one and use it.
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
PRUint16 platformID = GET_SHORT(p); // get platformID
|
|
p += sizeof(PRUint16); // move to platformSpecificID
|
|
PRUint16 encodingID = GET_SHORT(p); // get platformSpecificID
|
|
p += sizeof(PRUint16); // move to offset
|
|
offset = GET_LONG(p); // get offset
|
|
p += sizeof(PRUint32); // move to next entry
|
|
#ifdef DEBUG_TRUE_TYPE
|
|
printf("p=%d e=%d offset=%x\n", platformID, encodingID, offset);
|
|
#endif
|
|
if (platformID == kFontMicrosoftPlatform)
|
|
{
|
|
if (encodingID == kFontMicrosoftStandardScript)
|
|
{ // Unicode
|
|
// Some fonts claim to be unicode when they are actually
|
|
// 'pseudo-unicode' fonts that require a converter...
|
|
break; // break out from for(;;) loop
|
|
} //if (encodingID == kFontMicrosoftStandardScript)
|
|
#if 0
|
|
// if we have other encoding, we can still handle it, so... don't return this early
|
|
else if (encodingID == kFontMicrosoftSymbolScript)
|
|
{ // symbol
|
|
NS_ASSERTION(false, "cannot handle symbol font");
|
|
nsMemory::Free(buf);
|
|
return PR_FALSE;
|
|
}
|
|
#endif
|
|
} // if (platformID == kFontMicrosoftPlatform)
|
|
else {
|
|
if (platformID == kFontUnicodePlatform)
|
|
{ // Unicode
|
|
platformUnicodeOffset = offset;
|
|
}
|
|
}
|
|
} // for loop
|
|
|
|
NS_ASSERTION((i != n) || ( 0 != platformUnicodeOffset), "do not know the TrueType encoding");
|
|
if ((i == n) && ( 0 == platformUnicodeOffset))
|
|
{
|
|
nsMemory::Free(buf);
|
|
return PR_FALSE;
|
|
}
|
|
|
|
// usually, we come here for the entry platform = 3 encoding = 1
|
|
// or if we don't have it but we have a platform = 0 (platformUnicodeOffset != 0)
|
|
if(platformUnicodeOffset)
|
|
offset = platformUnicodeOffset;
|
|
|
|
p = buf + offset;
|
|
PRUint16 format = GET_SHORT(p);
|
|
NS_ASSERTION((kSFNTLookupSegmentArray == format), "hit some unknow format");
|
|
switch(format) {
|
|
case kSFNTLookupSegmentArray: // format 4
|
|
{
|
|
PRUint32 maxGlyph;
|
|
PRUint8* isSpace = GetSpaces(aFont, &maxGlyph);
|
|
// isSpace could be nsnull if the font do not have 'loca' table on Mac.
|
|
// Two reason for that:
|
|
// First, 'loca' table is not required in OpenType font.
|
|
//
|
|
// Second, on Mac, the sfnt-housed font may not have 'loca' table.
|
|
// exmaple are Beijing and Taipei font.
|
|
// see the WARNING section at the following link for details
|
|
// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
|
|
|
|
HandleFormat4((PRUint16*) (buf + offset), buf+len, isSpace, maxGlyph, aFontInfo);
|
|
|
|
if (isSpace)
|
|
nsMemory::Free(isSpace);
|
|
nsMemory::Free(buf);
|
|
return PR_TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
nsMemory::Free(buf);
|
|
return PR_FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRUint16* InitGlobalCCMap()
|
|
{
|
|
PRUint32 info[2048];
|
|
memset(info, 0, sizeof(info));
|
|
|
|
#ifdef TRACK_INIT_PERFORMANCE
|
|
AbsoluteTime startTime;
|
|
AbsoluteTime endTime;
|
|
startTime = UpTime();
|
|
#endif
|
|
|
|
FMFontFamilyIterator aFontIterator;
|
|
OSStatus status = 0;
|
|
FMFont aFont;
|
|
FMFontFamily aFontFamily;
|
|
status = ::FMCreateFontFamilyIterator(NULL, NULL, kFMDefaultOptions,
|
|
&aFontIterator);
|
|
while (status == noErr)
|
|
{
|
|
FourCharCode aFormat;
|
|
status = ::FMGetNextFontFamily(&aFontIterator, &aFontFamily);
|
|
OSStatus status2;
|
|
FMFontStyle aStyle;
|
|
status2 = ::FMGetFontFromFontFamilyInstance(aFontFamily, 0, &aFont, &aStyle);
|
|
NS_ASSERTION(status2 == noErr, "cannot get font from family");
|
|
if (status2 == noErr)
|
|
{
|
|
status2 = ::FMGetFontFormat(aFont, &aFormat);
|
|
#ifdef DEBUG_TRUE_TYPE
|
|
OSStatus status3 = ::FMGetFontFormat(aFont, &aFormat);
|
|
const char *four = (const char*) &aFormat;
|
|
Str255 familyName;
|
|
status3 = ::FMGetFontFamilyName(aFontFamily, familyName);
|
|
familyName[familyName[0]+1] = '\0';
|
|
printf("%s format = %c%c%c%c\n", familyName+1, *four, *(four+1), *(four+2), *(four+3));
|
|
#endif
|
|
if ((status2 == noErr) &&
|
|
((kFMTrueTypeFontTechnology == aFormat) ||
|
|
(kFMOpenTypeFontTechnology == aFormat)))
|
|
{
|
|
PRBool ret = FillFontInfoFromCMAP(aFont, info, aFormat);
|
|
}
|
|
}
|
|
}
|
|
// Dispose of the contents of the font iterator.
|
|
status = ::FMDisposeFontFamilyIterator(&aFontIterator);
|
|
|
|
PRUint16* map = MapToCCMap(info);
|
|
NS_ASSERTION(map, "cannot create the compressed map");
|
|
|
|
//register an observer to take care of cleanup
|
|
gFontCleanupObserver = new nsFontCleanupObserver();
|
|
NS_ASSERTION(gFontCleanupObserver, "failed to create observer");
|
|
if (gFontCleanupObserver) {
|
|
// register for shutdown
|
|
nsresult rv;
|
|
nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1", &rv));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
rv = observerService->AddObserver(gFontCleanupObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
|
|
}
|
|
}
|
|
|
|
#ifdef TRACK_INIT_PERFORMANCE
|
|
endTime = UpTime();
|
|
Nanoseconds diff = ::AbsoluteToNanoseconds(SubAbsoluteFromAbsolute(endTime, startTime));
|
|
printf("nsMacUnicodeFontInfo::InitGolbal take %d %d nanosecond\n", diff.hi, diff.lo);
|
|
#endif
|
|
|
|
return map;
|
|
}
|
|
|
|
// Helper to determine if a font has a private encoding that we know something about
|
|
static nsresult
|
|
GetEncoding(const nsCString& aFontName, nsACString& aValue)
|
|
{
|
|
nsresult rv;
|
|
// see if we should init the property
|
|
if (! gFontEncodingProperties) {
|
|
// but bail out for common fonts used at startup...
|
|
if (aFontName.EqualsLiteral("Lucida Grande") ||
|
|
aFontName.EqualsLiteral("Charcoal") ||
|
|
aFontName.EqualsLiteral("Chicago") ||
|
|
aFontName.EqualsLiteral("Capitals") ||
|
|
aFontName.EqualsLiteral("Gadget") ||
|
|
aFontName.EqualsLiteral("Sand") ||
|
|
aFontName.EqualsLiteral("Techno") ||
|
|
aFontName.EqualsLiteral("Textile") ||
|
|
aFontName.EqualsLiteral("Geneva") )
|
|
return NS_ERROR_NOT_AVAILABLE; // error mean do not get a special encoding
|
|
|
|
// init the property now
|
|
rv = NS_LoadPersistentPropertiesFromURISpec(&gFontEncodingProperties,
|
|
NS_LITERAL_CSTRING("resource:/res/fonts/fontEncoding.properties"));
|
|
if NS_FAILED(rv)
|
|
return rv;
|
|
}
|
|
|
|
nsCAutoString name(NS_LITERAL_CSTRING("encoding.") +
|
|
aFontName +
|
|
NS_LITERAL_CSTRING(".ttf"));
|
|
name.StripWhitespace();
|
|
ToLowerCase(name);
|
|
|
|
nsAutoString value;
|
|
rv = gFontEncodingProperties->GetStringProperty(name, value);
|
|
if (NS_SUCCEEDED(rv))
|
|
CopyUCS2toASCII(value, aValue);
|
|
return rv;
|
|
}
|
|
|
|
// This function uses the charset converter manager (CCM) to get a pointer on
|
|
// the converter for the font whose name is given. The CCM caches the converter.
|
|
// The caller holds a reference and should take care of the release.
|
|
static nsresult
|
|
GetConverter(const nsCString& aFontName, nsIUnicodeEncoder** aConverter)
|
|
{
|
|
*aConverter = nsnull;
|
|
|
|
nsCAutoString value;
|
|
nsresult rv = GetEncoding(aFontName, value);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!gCharsetManager)
|
|
{
|
|
rv = CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
|
|
if(NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
rv = gCharsetManager->GetUnicodeEncoderRaw(value.get(), aConverter);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsIUnicodeEncoder* tmp = *aConverter;
|
|
return tmp->SetOutputErrorBehavior(tmp->kOnError_Replace, nsnull, '?');
|
|
}
|
|
|
|
// This function uses the charset converter manager to fill the map for the
|
|
// font whose name is given
|
|
static PRUint16*
|
|
GetCCMapThroughConverter(nsIUnicodeEncoder *converter)
|
|
{
|
|
// see if we know something about the converter of this font
|
|
nsCOMPtr<nsICharRepresentable> mapper(do_QueryInterface(converter));
|
|
return (mapper ? MapperToCCMap(mapper) : nsnull);
|
|
}
|
|
|
|
static PRBool PR_CALLBACK
|
|
HashtableFreeCCMap(nsHashKey *aKey, void *aData, void *closure)
|
|
{
|
|
PRUint16* ccmap = (PRUint16*)aData;
|
|
FreeCCMap(ccmap);
|
|
return PR_TRUE;
|
|
}
|
|
|
|
// If the font is symbolic, get its converter and its compressed character map
|
|
// (CCMap). The caller holds a reference to the converter (@see GetConverter()).
|
|
// The CCMap is cached in a hashtable and will be freed at shutdown.
|
|
nsresult
|
|
nsMacUnicodeFontInfo::GetConverterAndCCMap(const nsString& aFontName, nsIUnicodeEncoder** aConverter,
|
|
PRUint16** aCCMap)
|
|
{
|
|
if(NS_SUCCEEDED(GetConverter(NS_ConvertUCS2toUTF8(aFontName), aConverter)) && *aConverter)
|
|
{
|
|
// make sure we have the hashtable
|
|
if(!gFontMaps)
|
|
{
|
|
gFontMaps = new nsObjectHashtable(nsnull, nsnull, HashtableFreeCCMap, nsnull);
|
|
if(!gFontMaps)
|
|
{
|
|
*aConverter = nsnull;
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
// first try to retrieve the ccmap for this font from the hashtable
|
|
nsStringKey hashKey(aFontName);
|
|
*aCCMap = (PRUint16*) gFontMaps->Get(&hashKey);
|
|
if(!*aCCMap)
|
|
{
|
|
// if it's not already in the hashtable, create it and add it to the hashtable
|
|
*aCCMap = GetCCMapThroughConverter(*aConverter);
|
|
if(!*aCCMap)
|
|
{
|
|
*aConverter = nsnull;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
gFontMaps->Put(&hashKey, *aCCMap);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
|
|
|
|
PRBool nsMacUnicodeFontInfo::HasGlyphFor(PRUnichar aChar)
|
|
{
|
|
if (0xfffd == aChar)
|
|
return PR_FALSE;
|
|
|
|
// MacOS 8.6 do not have FMxxx etc so we have to check
|
|
if (nsDeviceContextMac::HaveFontManager90()) {
|
|
if (!gCCMap)
|
|
gCCMap = InitGlobalCCMap();
|
|
|
|
NS_ASSERTION(gCCMap, "cannot init global ccmap");
|
|
|
|
if (gCCMap)
|
|
return CCMAP_HAS_CHAR(gCCMap, aChar);
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
void nsMacUnicodeFontInfo::FreeGlobals()
|
|
{
|
|
NS_IF_RELEASE(gFontEncodingProperties);
|
|
NS_IF_RELEASE(gCharsetManager);
|
|
|
|
delete gFontMaps;
|
|
if (gCCMap)
|
|
FreeCCMap(gCCMap);
|
|
}
|