Bug 532346: Work around ATSUI rendering failure with Apple LiGothic font on 10.6. r=roc

This commit is contained in:
Jonathan Kew 2009-12-10 12:18:14 -08:00
Родитель 1d8b996b9f
Коммит 90dffcabd4
7 изменённых файлов: 203 добавлений и 28 удалений

Просмотреть файл

@ -55,6 +55,9 @@ class gfxAtsuiFontGroup;
class MacOSFontEntry;
#define kLiGothicBadCharUnicode 0x775B // ATSUI failure on 10.6 (bug 532346)
#define kLiGothicBadCharGlyph 3774 // the expected glyph for this char
class gfxAtsuiFont : public gfxFont {
public:

Просмотреть файл

@ -476,10 +476,20 @@ public:
ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength,
gfxSparseBitSet& aCharacterMap);
static PRUint32
FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
PRUint32 *aTableOffset, PRBool *aSymbolEncoding);
static nsresult
ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont);
static PRUint32
MapCharToGlyphFormat4(const PRUint8 *aBuf, PRUnichar aCh);
static PRUint32
MapCharToGlyph(PRUint8 *aBuf, PRUint32 aBufLength, PRUnichar aCh);
#ifdef XP_WIN
// given a TrueType/OpenType data file, produce a EOT-format header

Просмотреть файл

@ -44,6 +44,9 @@
#define MAC_OS_X_VERSION_10_4_HEX 0x00001040
#define MAC_OS_X_VERSION_10_5_HEX 0x00001050
#define MAC_OS_X_VERSION_10_6_HEX 0x00001060
#define MAC_OS_X_MAJOR_VERSION_MASK 0xFFFFFFF0U
class gfxTextRun;

Просмотреть файл

@ -1468,6 +1468,14 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
PRUint32 r, numRanges = fontRanges.Length();
// Bug 532346: Work around rendering failure with Apple LiGothic font on 10.6,
// triggered by U+775B.
// We record the offset(s) in layoutString where this character occurs, and replace
// them with U+775C, which has the same metrics but doesn't disrupt ATSUI layout.
// Then after layout is complete, we poke the correct glyph for U+775B into the
// text run at the recorded positions.
nsTArray<PRUint32> hackForLiGothic;
for (r = 0; r < numRanges; r++) {
const gfxTextRange& range = fontRanges[r];
@ -1518,6 +1526,19 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
// add a glyph run for the matched substring
aRun->AddGlyphRun(matchedFont, aOffsetInTextRun + runStart - aLayoutStart, PR_TRUE);
if (matchedFont->GetFontEntry()->UseLiGothicAtsuiHack()) {
PRUnichar *text = const_cast<PRUnichar*>(layoutString);
for (PRUint32 i = 0; i < matchedLength; ++i) {
if (text[aOffsetInTextRun + runStart + i] ==
kLiGothicBadCharUnicode) {
hackForLiGothic.AppendElement(aOffsetInTextRun +
runStart + i);
text[aOffsetInTextRun + runStart + i] =
kLiGothicBadCharUnicode + 1;
}
}
}
}
runStart += matchedLength;
@ -1542,6 +1563,16 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
aRun->AdjustAdvancesForSyntheticBold(aOffsetInTextRun, aLengthInTextRun);
for (PRUint32 i = 0; i < hackForLiGothic.Length(); ++i) {
gfxTextRun::CompressedGlyph glyph =
aRun->GetCharacterGlyphs()[hackForLiGothic[i]];
if (glyph.IsSimpleGlyph()) {
aRun->SetSimpleGlyph(hackForLiGothic[i],
glyph.SetSimpleGlyph(glyph.GetSimpleAdvance(),
kLiGothicBadCharGlyph));
}
}
PRUint32 i;
for (i = 0; i < stylesToDispose.Length(); ++i) {
ATSUDisposeStyle(stylesToDispose[i]);

Просмотреть файл

@ -373,9 +373,9 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBit
((platformID == PLATFORM_ID_MICROSOFT && encodingID == EncodingIDUCS4ForMicrosoftPlatform) || \
(platformID == PLATFORM_ID_UNICODE && encodingID == EncodingIDUCS4ForUnicodePlatform))
nsresult
gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont)
PRUint32
gfxFontUtils::FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
PRUint32 *aTableOffset, PRBool *aSymbolEncoding)
{
enum {
OffsetVersion = 0,
@ -399,8 +399,7 @@ gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCha
// PRUint16 version = ReadShortAt(aBuf, OffsetVersion); // Unused: self-documenting.
PRUint16 numTables = ReadShortAt(aBuf, OffsetNumTables);
// save the format and offset we want here
PRUint32 keepOffset = 0;
// save the format we want here
PRUint32 keepFormat = 0;
PRUint8 *table = aBuf + SizeOfHeader;
@ -419,33 +418,144 @@ gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCha
const PRUint16 format = ReadShortAt(subtable, SubtableOffsetFormat);
if (isSymbol(platformID, encodingID)) {
aUnicodeFont = PR_FALSE;
aSymbolFont = PR_TRUE;
keepFormat = format;
keepOffset = offset;
*aTableOffset = offset;
*aSymbolEncoding = PR_TRUE;
break;
} else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
aUnicodeFont = PR_TRUE;
aSymbolFont = PR_FALSE;
keepFormat = format;
keepOffset = offset;
*aTableOffset = offset;
*aSymbolEncoding = PR_FALSE;
} else if (format == 12 && acceptableUCS4Encoding(platformID, encodingID)) {
aUnicodeFont = PR_TRUE;
aSymbolFont = PR_FALSE;
keepFormat = format;
keepOffset = offset;
*aTableOffset = offset;
*aSymbolEncoding = PR_FALSE;
break; // we don't want to try anything else when this format is available.
}
}
nsresult rv = NS_ERROR_FAILURE;
return keepFormat;
}
if (keepFormat == 12)
rv = ReadCMAPTableFormat12(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap);
else if (keepFormat == 4)
rv = ReadCMAPTableFormat4(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap);
nsresult
gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont)
{
PRUint32 offset;
PRBool symbol;
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset, &symbol);
return rv;
if (format == 4) {
if (symbol) {
aUnicodeFont = PR_FALSE;
aSymbolFont = PR_TRUE;
} else {
aUnicodeFont = PR_TRUE;
aSymbolFont = PR_FALSE;
}
return ReadCMAPTableFormat4(aBuf + offset, aBufLength - offset, aCharacterMap);
}
if (format == 12) {
aUnicodeFont = PR_TRUE;
aSymbolFont = PR_FALSE;
return ReadCMAPTableFormat12(aBuf + offset, aBufLength - offset, aCharacterMap);
}
return NS_ERROR_FAILURE;
}
using namespace mozilla; // for the AutoSwap_* types
#pragma pack(1)
typedef struct {
AutoSwap_PRUint16 format;
AutoSwap_PRUint16 length;
AutoSwap_PRUint16 language;
AutoSwap_PRUint16 segCountX2;
AutoSwap_PRUint16 searchRange;
AutoSwap_PRUint16 entrySelector;
AutoSwap_PRUint16 rangeShift;
AutoSwap_PRUint16 arrays[1];
} Format4Cmap;
PRUint32
gfxFontUtils::MapCharToGlyphFormat4(const PRUint8 *aBuf, PRUnichar aCh)
{
const Format4Cmap *cmap4 = reinterpret_cast<const Format4Cmap*>(aBuf);
PRUint16 segCount;
const AutoSwap_PRUint16 *endCodes;
const AutoSwap_PRUint16 *startCodes;
const AutoSwap_PRUint16 *idDelta;
const AutoSwap_PRUint16 *idRangeOffset;
PRUint16 probe;
PRUint16 rangeShiftOver2;
PRUint16 index;
// not needed because PRUnichar cannot exceed 0xFFFF
// if (aCh >= 0x10000) {
// return 0;
// }
segCount = (PRUint16)(cmap4->segCountX2) / 2;
endCodes = &cmap4->arrays[0];
startCodes = &cmap4->arrays[segCount + 1]; // +1 for reserved word between arrays
idDelta = &startCodes[segCount];
idRangeOffset = &idDelta[segCount];
probe = 1 << (PRUint16)(cmap4->entrySelector);
rangeShiftOver2 = (PRUint16)(cmap4->rangeShift) / 2;
if ((PRUint16)(startCodes[rangeShiftOver2]) <= aCh) {
index = rangeShiftOver2;
} else {
index = 0;
}
while (probe > 1) {
probe >>= 1;
if ((PRUint16)(startCodes[index + probe]) <= aCh) {
index += probe;
}
}
if (aCh >= (PRUint16)(startCodes[index]) && aCh <= (PRUint16)(endCodes[index])) {
PRUint16 result;
if ((PRUint16)(idRangeOffset[index]) == 0) {
result = aCh;
} else {
PRUint16 offset = aCh - (PRUint16)(startCodes[index]);
const AutoSwap_PRUint16 *glyphIndexTable =
(const AutoSwap_PRUint16*)((const char*)&idRangeOffset[index] +
(PRUint16)(idRangeOffset[index]));
result = glyphIndexTable[offset];
}
// note that this is unsigned 16-bit arithmetic, and may wrap around
result += (PRUint16)(idDelta[index]);
return result;
}
return 0;
}
PRUint32
gfxFontUtils::MapCharToGlyph(PRUint8 *aBuf, PRUint32 aBufLength, PRUnichar aCh)
{
PRUint32 offset;
PRBool symbol;
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset, &symbol);
if (format == 4)
return MapCharToGlyphFormat4(aBuf + offset, aCh);
// other formats not currently supported; this is used only for the
// Mac OS X 10.6 LiGothic font hack (bug 532346)
return 0;
}
PRUint8 gfxFontUtils::CharRangeBit(PRUint32 ch) {
@ -538,8 +648,6 @@ nsresult gfxFontUtils::MakeUniqueUserFontName(nsAString& aName)
// TrueType/OpenType table handling code
using namespace mozilla; // for the AutoSwap_* types
// need byte aligned structs
#pragma pack(1)

Просмотреть файл

@ -70,6 +70,8 @@ public:
ATSFontRef GetFontRef();
nsresult ReadCMAP();
PRBool UseLiGothicAtsuiHack() { return mUseLiGothicAtsuiHack; }
protected:
// for use with data fonts
MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef,
@ -80,6 +82,7 @@ protected:
ATSFontRef mATSFontRef;
PRPackedBool mATSFontRefInitialized;
PRPackedBool mUseLiGothicAtsuiHack;
};
class gfxMacPlatformFontList : public gfxPlatformFontList {

Просмотреть файл

@ -117,7 +117,8 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
PRBool aIsStandardFace)
: gfxFontEntry(aPostscriptName, aFamily, aIsStandardFace),
mATSFontRef(0),
mATSFontRefInitialized(PR_FALSE)
mATSFontRefInitialized(PR_FALSE),
mUseLiGothicAtsuiHack(PR_FALSE)
{
mWeight = aWeight;
}
@ -127,7 +128,8 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFon
gfxUserFontData *aUserFontData)
: gfxFontEntry(aPostscriptName),
mATSFontRef(aFontRef),
mATSFontRefInitialized(PR_TRUE)
mATSFontRefInitialized(PR_TRUE),
mUseLiGothicAtsuiHack(PR_FALSE)
{
// xxx - stretch is basically ignored for now
@ -189,13 +191,12 @@ MacOSFontEntry::ReadCMAP()
PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p');
nsAutoTArray<PRUint8,16384> buffer;
if (GetFontTable(kCMAP, buffer) != NS_OK)
nsAutoTArray<PRUint8,16384> cmap;
if (GetFontTable(kCMAP, cmap) != NS_OK)
return NS_ERROR_FAILURE;
PRUint8 *cmap = buffer.Elements();
PRPackedBool unicodeFont, symbolFont; // currently ignored
nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
nsresult rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
mCharacterMap, unicodeFont, symbolFont);
if (NS_FAILED(rv)) {
@ -264,6 +265,22 @@ MacOSFontEntry::ReadCMAP()
}
}
if ((gfxPlatformMac::GetPlatform()->OSXVersion() &
MAC_OS_X_MAJOR_VERSION_MASK) == MAC_OS_X_VERSION_10_6_HEX) {
// even ruder hack - LiGothic font on 10.6 has a bad glyph for U+775B
// that causes ATSUI failure, so we set a flag to tell our layout code
// to hack around that character
if (mName.EqualsLiteral("LiGothicMed")) {
// check whether the problem char maps to the expected glyph;
// if not, we'll assume this isn't the problem version of the font
if (gfxFontUtils::MapCharToGlyph(cmap.Elements(), cmap.Length(),
kLiGothicBadCharUnicode) ==
kLiGothicBadCharGlyph) {
mUseLiGothicAtsuiHack = PR_TRUE;
}
}
}
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-cmap) psname: %s, size: %d\n",
NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));