Bug 463806 - [PATCH][@font-face] Downloaded font activation on Mac may fail due to ATS cache corruption; r=(jdaggett + roc) sr=roc

This commit is contained in:
Jonathan Kew 2008-12-21 02:26:18 +01:00
parent 44016eb6da
commit 7306315f29
2 changed files with 109 additions and 80 deletions

View File

@ -85,7 +85,9 @@ public:
protected:
// for use with data fonts
MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, gfxUserFontData *aUserFontData);
MacOSFontEntry(const nsAString& aPostscriptName, ATSUFontID aFontID,
PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle,
gfxUserFontData *aUserFontData);
PRUint32 mTraits;
MacOSFamilyEntry *mFamily;

View File

@ -2,12 +2,13 @@
* ***** BEGIN LICENSE BLOCK *****
* Version: BSD
*
* Copyright (C) 2006 Mozilla Corporation. All rights reserved.
* Copyright (C) 2006-2008 Mozilla Corporation. All rights reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* John Daggett <jdaggett@mozilla.com>
* Jonathan Kew <jfkthame@gmail.com>
*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
*
@ -117,7 +118,7 @@ gfxQuartzFontCache::GenerateFontListKey(const nsAString& aKeyName, nsAString& aR
#pragma mark-
MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
PRInt32 aAppleWeight, PRUint32 aTraits, MacOSFamilyEntry *aFamily)
PRInt32 aAppleWeight, PRUint32 aTraits, MacOSFamilyEntry *aFamily)
: gfxFontEntry(aPostscriptName), mTraits(aTraits), mFamily(aFamily), mATSUFontID(0),
mATSUIDInitialized(0)
{
@ -127,10 +128,12 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
mFixedPitch = (mTraits & NSFixedPitchFontMask ? 1 : 0);
}
MacOSFontEntry::MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, gfxUserFontData *aUserFontData)
MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, ATSUFontID aFontID,
PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle,
gfxUserFontData *aUserFontData)
{
// xxx - stretch is basically ignored for now
mATSUIDInitialized = PR_TRUE;
mATSUFontID = aFontID;
mUserFontData = aUserFontData;
@ -143,23 +146,7 @@ MacOSFontEntry::MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aS
(mFixedPitch ? NSFixedPitchFontMask : 0) |
(mWeight >= 600 ? NSBoldFontMask : NSUnboldFontMask);
// get the postscript name
OSStatus err;
NSString *psname = NULL;
// now lookup the Postscript name
err = ATSFontGetPostScriptName((ATSFontRef) aFontID, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
if (err == noErr) {
GetStringForNSString(psname, mName);
[psname release];
} else {
mIsValid = PR_FALSE;
#ifdef DEBUG
char warnBuf[1024];
sprintf(warnBuf, "ATSFontGetPostScriptName err = %d", (PRInt32)err);
NS_WARNING(warnBuf);
#endif
}
mName = aPostscriptName;
}
const nsString&
@ -706,7 +693,7 @@ const PRUint32 kNonNormalTraits = NSItalicFontMask | NSBoldFontMask | NSNarrowFo
void
gfxQuartzFontCache::InitFontList()
{
ATSGeneration currentGeneration = ATSGeneration();
ATSGeneration currentGeneration = ATSGetGeneration();
// need to ignore notifications after adding each font
if (mATSGeneration == currentGeneration)
@ -1338,73 +1325,106 @@ gfxQuartzFontCache::MakePlatformFont(const gfxFontEntry *aProxyEntry,
return nsnull;
}
ATSUFontID fontID;
ATSFontRef fontRef;
ATSFontContainerRef containerRef;
err = ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
kPrivateATSFontContextPrivate,
kATSFontFormatUnspecified,
NULL,
kATSOptionFlagsDoNotNotify,
&containerRef);
// we get occasional failures when multiple fonts are activated in quick succession
// if the ATS font cache is damaged; to work around this, we can retry the activation
const PRUint32 kMaxRetries = 3;
PRUint32 retryCount = 0;
while (retryCount++ < kMaxRetries) {
err = ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
kPrivateATSFontContextPrivate,
kATSFontFormatUnspecified,
NULL,
kATSOptionFlagsDoNotNotify,
&containerRef);
mATSGeneration = ATSGetGeneration();
if (err != noErr) {
if (err != noErr) {
#if DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d for (%s)",
PRInt32(err),
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d for (%s)",
PRInt32(err),
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
return nsnull;
}
return nsnull;
}
mATSGeneration = ATSGeneration();
// ignoring containers with multiple fonts, use the first face only for now
err = ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
(ATSFontRef*)&fontID, NULL);
if (err != noErr) {
// ignoring containers with multiple fonts, use the first face only for now
err = ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
&fontRef, NULL);
if (err != noErr) {
#if DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d for (%s)",
PRInt32(err),
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d for (%s)",
PRInt32(err),
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
return nsnull;
}
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
return nsnull;
}
// font entry will own this
MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef);
if (!userFontData) {
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
return nsnull;
}
// now lookup the Postscript name; this may fail if the font cache is bad
OSStatus err;
NSString *psname = NULL;
nsAutoString postscriptName;
err = ATSFontGetPostScriptName(fontRef, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
if (err == noErr) {
GetStringForNSString(psname, postscriptName);
[psname release];
} else {
#ifdef DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "ATSFontGetPostScriptName err = %d for (%s), retries = %d", (PRInt32)err,
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get(), retryCount);
NS_WARNING(warnBuf);
#endif
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
// retry the activation a couple of times if this fails
// (may be a transient failure due to ATS font cache issues)
continue;
}
PRUint16 w = aProxyEntry->mWeight;
NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
// font entry will own this
MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef);
MacOSFontEntry *newFontEntry =
new MacOSFontEntry(fontID, w, aProxyEntry->mStretch,
(PRUint32(aProxyEntry->mItalic) ?
FONT_STYLE_ITALIC :
FONT_STYLE_NORMAL),
userFontData);
if (!userFontData) {
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
return nsnull;
}
if (!newFontEntry) {
delete userFontData;
return nsnull;
}
// if something is funky about this font, delete immediately
if (newFontEntry && !newFontEntry->mIsValid) {
PRUint16 w = aProxyEntry->mWeight;
NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
// create the font entry
MacOSFontEntry *newFontEntry =
new MacOSFontEntry(postscriptName,
FMGetFontFromATSFontRef(fontRef),
w, aProxyEntry->mStretch,
(PRUint32(aProxyEntry->mItalic) ?
FONT_STYLE_ITALIC :
FONT_STYLE_NORMAL),
userFontData);
if (!newFontEntry) {
delete userFontData;
return nsnull;
}
// if we succeeded (which should always be the case), return the new font
if (newFontEntry->mIsValid)
return newFontEntry;
// if something is funky about this font, delete immediately
#if DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
@ -1414,10 +1434,17 @@ gfxQuartzFontCache::MakePlatformFont(const gfxFontEntry *aProxyEntry,
NS_WARNING(warnBuf);
#endif
delete newFontEntry;
return nsnull;
// We don't retry from here; the ATS font cache issue would have caused failure earlier
// so if we get here, there's something else bad going on within our font data structures.
// Currently, there should be no way to reach here, as fontentry creation cannot fail
// except by memory allocation failure.
NS_WARNING("invalid font entry for a newly activated font");
break;
}
return newFontEntry;
// if we get here, the activation failed (even with possible retries); can't use this font
return nsnull;
}