зеркало из https://github.com/mozilla/gecko-dev.git
Bug 532346: Work around ATSUI rendering failure with Apple LiGothic font on 10.6. r=roc
This commit is contained in:
Родитель
1d8b996b9f
Коммит
90dffcabd4
|
@ -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()));
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче