mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 361986. Exclude complex script codepoints for fonts that lack AAT morphing data. r=vlad,smontagu, sr=pavlov
This commit is contained in:
parent
45477e7a1d
commit
94f07ba724
@ -59,9 +59,10 @@
|
|||||||
|
|
||||||
class gfxSparseBitSet {
|
class gfxSparseBitSet {
|
||||||
private:
|
private:
|
||||||
enum { BLOCK_SIZE = 32 };
|
enum { BLOCK_SIZE = 32 }; // ==> 256 codepoints per block
|
||||||
enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
|
enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
|
||||||
|
enum { BLOCK_INDEX_SHIFT = 8 };
|
||||||
|
|
||||||
struct Block {
|
struct Block {
|
||||||
Block(unsigned char memsetValue = 0) { memset(mBits, memsetValue, BLOCK_SIZE); }
|
Block(unsigned char memsetValue = 0) { memset(mBits, memsetValue, BLOCK_SIZE); }
|
||||||
PRUint8 mBits[BLOCK_SIZE];
|
PRUint8 mBits[BLOCK_SIZE];
|
||||||
@ -75,9 +76,67 @@ public:
|
|||||||
Block *block = mBlocks[blockIndex];
|
Block *block = mBlocks[blockIndex];
|
||||||
if (!block)
|
if (!block)
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
return ((block->mBits[(aIndex/8) & (BLOCK_SIZE - 1)]) & (1 << (aIndex & 0x7))) != 0;
|
return ((block->mBits[(aIndex>>3) & (BLOCK_SIZE - 1)]) & (1 << (aIndex & 0x7))) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRBool TestRange(PRUint32 aStart, PRUint32 aEnd) {
|
||||||
|
PRUint32 startBlock, endBlock, blockLen;
|
||||||
|
|
||||||
|
// start point is beyond the end of the block array? return false immediately
|
||||||
|
startBlock = aStart >> BLOCK_INDEX_SHIFT;
|
||||||
|
blockLen = mBlocks.Length();
|
||||||
|
if (startBlock >= blockLen) return PR_FALSE;
|
||||||
|
|
||||||
|
// check for blocks in range, if none, return false
|
||||||
|
PRUint32 blockIndex;
|
||||||
|
PRBool hasBlocksInRange = PR_FALSE;
|
||||||
|
|
||||||
|
endBlock = aEnd >> BLOCK_INDEX_SHIFT;
|
||||||
|
blockIndex = startBlock;
|
||||||
|
for (blockIndex = startBlock; blockIndex <= endBlock; blockIndex++) {
|
||||||
|
if (blockIndex < blockLen && mBlocks[blockIndex])
|
||||||
|
hasBlocksInRange = PR_TRUE;
|
||||||
|
}
|
||||||
|
if (!hasBlocksInRange) return PR_FALSE;
|
||||||
|
|
||||||
|
Block *block;
|
||||||
|
PRUint32 i, start, end;
|
||||||
|
|
||||||
|
// first block, check bits
|
||||||
|
if ((block = mBlocks[startBlock])) {
|
||||||
|
start = aStart;
|
||||||
|
end = PR_MIN(aEnd, ((startBlock+1) << BLOCK_INDEX_SHIFT) - 1);
|
||||||
|
for (i = start; i <= end; i++) {
|
||||||
|
if ((block->mBits[(i>>3) & (BLOCK_SIZE - 1)]) & (1 << (i & 0x7)))
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (endBlock == startBlock) return PR_FALSE;
|
||||||
|
|
||||||
|
// [2..n-1] blocks check bytes
|
||||||
|
for (blockIndex = startBlock + 1; blockIndex < endBlock; blockIndex++) {
|
||||||
|
PRUint32 index;
|
||||||
|
|
||||||
|
if (blockIndex >= blockLen || !(block = mBlocks[blockIndex])) continue;
|
||||||
|
for (index = 0; index < BLOCK_SIZE; index++) {
|
||||||
|
if (block->mBits[index])
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// last block, check bits
|
||||||
|
if (endBlock < blockLen && (block = mBlocks[endBlock])) {
|
||||||
|
start = endBlock << BLOCK_INDEX_SHIFT;
|
||||||
|
end = aEnd;
|
||||||
|
for (i = start; i <= end; i++) {
|
||||||
|
if ((block->mBits[(i>>3) & (BLOCK_SIZE - 1)]) & (1 << (i & 0x7)))
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void set(PRUint32 aIndex) {
|
void set(PRUint32 aIndex) {
|
||||||
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
|
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
|
||||||
if (blockIndex >= mBlocks.Length()) {
|
if (blockIndex >= mBlocks.Length()) {
|
||||||
@ -92,7 +151,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
mBlocks[blockIndex] = block;
|
mBlocks[blockIndex] = block;
|
||||||
}
|
}
|
||||||
block->mBits[(aIndex/8) & (BLOCK_SIZE - 1)] |= 1 << (aIndex & 0x7);
|
block->mBits[(aIndex>>3) & (BLOCK_SIZE - 1)] |= 1 << (aIndex & 0x7);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRange(PRUint32 aStart, PRUint32 aEnd) {
|
void SetRange(PRUint32 aStart, PRUint32 aEnd) {
|
||||||
@ -130,7 +189,64 @@ public:
|
|||||||
const PRUint32 end = PR_MIN(aEnd - blockFirstBit, BLOCK_SIZE_BITS - 1);
|
const PRUint32 end = PR_MIN(aEnd - blockFirstBit, BLOCK_SIZE_BITS - 1);
|
||||||
|
|
||||||
for (PRUint32 bit = start; bit <= end; ++bit) {
|
for (PRUint32 bit = start; bit <= end; ++bit) {
|
||||||
block->mBits[bit/8] |= 1 << (bit & 0x7);
|
block->mBits[bit>>3] |= 1 << (bit & 0x7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(PRUint32 aIndex) {
|
||||||
|
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
|
||||||
|
if (blockIndex >= mBlocks.Length()) {
|
||||||
|
nsAutoPtr<Block> *blocks = mBlocks.AppendElements(blockIndex + 1 - mBlocks.Length());
|
||||||
|
if (NS_UNLIKELY(!blocks)) // OOM
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Block *block = mBlocks[blockIndex];
|
||||||
|
if (!block) {
|
||||||
|
block = new Block;
|
||||||
|
if (NS_UNLIKELY(!block)) // OOM
|
||||||
|
return;
|
||||||
|
mBlocks[blockIndex] = block;
|
||||||
|
}
|
||||||
|
block->mBits[(aIndex>>3) & (BLOCK_SIZE - 1)] &= ~(1 << (aIndex & 0x7));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearRange(PRUint32 aStart, PRUint32 aEnd) {
|
||||||
|
const PRUint32 startIndex = aStart/BLOCK_SIZE_BITS;
|
||||||
|
const PRUint32 endIndex = aEnd/BLOCK_SIZE_BITS;
|
||||||
|
|
||||||
|
if (endIndex >= mBlocks.Length()) {
|
||||||
|
PRUint32 numNewBlocks = endIndex + 1 - mBlocks.Length();
|
||||||
|
nsAutoPtr<Block> *blocks = mBlocks.AppendElements(numNewBlocks);
|
||||||
|
if (NS_UNLIKELY(!blocks)) // OOM
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PRUint32 i = startIndex; i <= endIndex; ++i) {
|
||||||
|
const PRUint32 blockFirstBit = i * BLOCK_SIZE_BITS;
|
||||||
|
const PRUint32 blockLastBit = blockFirstBit + BLOCK_SIZE_BITS - 1;
|
||||||
|
|
||||||
|
Block *block = mBlocks[i];
|
||||||
|
if (!block) {
|
||||||
|
PRBool fullBlock = PR_FALSE;
|
||||||
|
if (aStart <= blockFirstBit && aEnd >= blockLastBit)
|
||||||
|
fullBlock = PR_TRUE;
|
||||||
|
|
||||||
|
block = new Block(fullBlock ? 0xFF : 0);
|
||||||
|
|
||||||
|
if (NS_UNLIKELY(!block)) // OOM
|
||||||
|
return;
|
||||||
|
mBlocks[i] = block;
|
||||||
|
|
||||||
|
if (fullBlock)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PRUint32 start = aStart > blockFirstBit ? aStart - blockFirstBit : 0;
|
||||||
|
const PRUint32 end = PR_MIN(aEnd - blockFirstBit, BLOCK_SIZE_BITS - 1);
|
||||||
|
|
||||||
|
for (PRUint32 bit = start; bit <= end; ++bit) {
|
||||||
|
block->mBits[bit>>3] &= ~(1 << (bit & 0x7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,30 @@ ATSUFontID MacOSFontEntry::GetFontID()
|
|||||||
return mATSUFontID;
|
return mATSUFontID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ATSUI requires AAT-enabled fonts to render complex scripts correctly.
|
||||||
|
// For now, simple clear out the cmap codepoints for fonts that have
|
||||||
|
// codepoints for complex scripts. (Bug 361986)
|
||||||
|
|
||||||
|
enum eComplexScript {
|
||||||
|
eComplexScriptArabic,
|
||||||
|
eComplexScriptIndic,
|
||||||
|
eComplexScriptTibetan
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScriptRange {
|
||||||
|
eComplexScript script;
|
||||||
|
PRUint32 rangeStart;
|
||||||
|
PRUint32 rangeEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ScriptRange gScriptsThatRequireShaping[] = {
|
||||||
|
{ eComplexScriptArabic, 0x0600, 0x077F }, // Basic Arabic and Arabic Supplement
|
||||||
|
{ eComplexScriptIndic, 0x0900, 0x0D7F }, // Indic scripts - Devanagari, Bengali, ..., Malayalam
|
||||||
|
{ eComplexScriptTibetan, 0x0F00, 0x0FFF } // Tibetan
|
||||||
|
// Thai seems to be "renderable" without AAT morphing tables
|
||||||
|
// xxx - Lao, Khmer?
|
||||||
|
};
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
MacOSFontEntry::ReadCMAP()
|
MacOSFontEntry::ReadCMAP()
|
||||||
{
|
{
|
||||||
@ -167,7 +191,49 @@ MacOSFontEntry::ReadCMAP()
|
|||||||
nsresult rv = NS_ERROR_FAILURE;
|
nsresult rv = NS_ERROR_FAILURE;
|
||||||
PRPackedBool unicodeFont, symbolFont; // currently ignored
|
PRPackedBool unicodeFont, symbolFont; // currently ignored
|
||||||
rv = gfxFontUtils::ReadCMAP(cmap, size, mCharacterMap, mUnicodeRanges, unicodeFont, symbolFont);
|
rv = gfxFontUtils::ReadCMAP(cmap, size, mCharacterMap, mUnicodeRanges, unicodeFont, symbolFont);
|
||||||
|
|
||||||
|
// for complex scripts, check for the presence of mort/morx
|
||||||
|
PRBool checkedForMorphTable = PR_FALSE, hasMorphTable = PR_FALSE;
|
||||||
|
|
||||||
|
PRUint32 s, numScripts = sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange);
|
||||||
|
|
||||||
|
for (s = 0; s < numScripts; s++) {
|
||||||
|
eComplexScript whichScript = gScriptsThatRequireShaping[s].script;
|
||||||
|
|
||||||
|
// check to see if the cmap includes complex script codepoints
|
||||||
|
if (mCharacterMap.TestRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd)) {
|
||||||
|
|
||||||
|
// check for mort/morx table, if haven't already
|
||||||
|
if (!checkedForMorphTable) {
|
||||||
|
status = ATSFontGetTable(fontID, 'morx', 0, 0, 0, &size);
|
||||||
|
if ( status == noErr ) {
|
||||||
|
checkedForMorphTable = PR_TRUE;
|
||||||
|
hasMorphTable = PR_TRUE;
|
||||||
|
} else {
|
||||||
|
// check for a mort table
|
||||||
|
status = ATSFontGetTable(fontID, 'mort', 0, 0, 0, &size);
|
||||||
|
checkedForMorphTable = PR_TRUE;
|
||||||
|
if ( status == noErr ) {
|
||||||
|
hasMorphTable = PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rude hack - the Chinese STxxx fonts on 10.4 contain morx tables and Arabic glyphs but
|
||||||
|
// lack the proper info for shaping Arabic, so exclude explicitly, ick
|
||||||
|
if (whichScript == eComplexScriptArabic && hasMorphTable) {
|
||||||
|
if (mPostscriptName.CharAt(0) == 'S' && mPostscriptName.CharAt(1) == 'T') {
|
||||||
|
mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// general exclusion - if no morph table, exclude codepoints
|
||||||
|
if (!hasMorphTable) {
|
||||||
|
mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user