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 {
|
||||
private:
|
||||
enum { BLOCK_SIZE = 32 };
|
||||
enum { BLOCK_SIZE = 32 }; // ==> 256 codepoints per block
|
||||
enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
|
||||
|
||||
enum { BLOCK_INDEX_SHIFT = 8 };
|
||||
|
||||
struct Block {
|
||||
Block(unsigned char memsetValue = 0) { memset(mBits, memsetValue, BLOCK_SIZE); }
|
||||
PRUint8 mBits[BLOCK_SIZE];
|
||||
@ -75,9 +76,67 @@ public:
|
||||
Block *block = mBlocks[blockIndex];
|
||||
if (!block)
|
||||
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) {
|
||||
PRUint32 blockIndex = aIndex/BLOCK_SIZE_BITS;
|
||||
if (blockIndex >= mBlocks.Length()) {
|
||||
@ -92,7 +151,7 @@ public:
|
||||
return;
|
||||
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) {
|
||||
@ -130,7 +189,64 @@ public:
|
||||
const PRUint32 end = PR_MIN(aEnd - blockFirstBit, BLOCK_SIZE_BITS - 1);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
MacOSFontEntry::ReadCMAP()
|
||||
{
|
||||
@ -167,7 +191,49 @@ MacOSFontEntry::ReadCMAP()
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
PRPackedBool unicodeFont, symbolFont; // currently ignored
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user