bug 552460 - part 3 - implement Variation Sequence support in Windows font backend. r=jfkthame

This commit is contained in:
Masatoshi Kimura 2010-06-01 14:42:37 +01:00
Родитель dd7dd2083e
Коммит caca11adda
12 изменённых файлов: 373 добавлений и 57 удалений

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

@ -79,7 +79,6 @@ public:
mFTFontIndex = 0;
}
FontEntry(const FontEntry& aFontEntry);
~FontEntry();
const nsString& GetName() const {

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

@ -171,22 +171,12 @@ public:
mStandardFace(aIsStandardFace),
mSymbolFont(PR_FALSE),
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
mCmapInitialized(PR_FALSE), mUserFontData(nsnull),
mCmapInitialized(PR_FALSE),
mUVSOffset(0), mUVSData(nsnull),
mUserFontData(nsnull),
mFamily(aFamily)
{ }
gfxFontEntry(const gfxFontEntry& aEntry) :
mName(aEntry.mName), mItalic(aEntry.mItalic),
mFixedPitch(aEntry.mFixedPitch), mIsProxy(aEntry.mIsProxy),
mIsValid(aEntry.mIsValid), mIsBadUnderlineFont(aEntry.mIsBadUnderlineFont),
mIsUserFont(aEntry.mIsUserFont),
mStandardFace(aEntry.mStandardFace),
mSymbolFont(aEntry.mSymbolFont),
mWeight(aEntry.mWeight), mCmapInitialized(aEntry.mCmapInitialized),
mCharacterMap(aEntry.mCharacterMap), mUserFontData(aEntry.mUserFontData),
mFamily(aEntry.mFamily)
{ }
virtual ~gfxFontEntry();
// unique name for the face, *not* the family
@ -204,11 +194,13 @@ public:
inline PRBool HasCharacter(PRUint32 ch) {
if (mCharacterMap.test(ch))
return PR_TRUE;
return TestCharacterMap(ch);
}
virtual PRBool TestCharacterMap(PRUint32 aCh);
nsresult InitializeUVSMap();
PRUint16 GetUVSGlyph(PRUint32 aCh, PRUint32 aVS);
virtual nsresult ReadCMAP();
virtual PRBool MatchesGenericFamily(const nsACString& aGeneric) const {
@ -242,6 +234,8 @@ public:
PRPackedBool mCmapInitialized;
gfxSparseBitSet mCharacterMap;
PRUint32 mUVSOffset;
nsAutoArrayPtr<PRUint8> mUVSData;
gfxUserFontData* mUserFontData;
protected:
@ -260,6 +254,7 @@ protected:
mSymbolFont(PR_FALSE),
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
mCmapInitialized(PR_FALSE),
mUVSOffset(0), mUVSData(nsnull),
mUserFontData(nsnull),
mFamily(nsnull)
{ }
@ -274,6 +269,10 @@ protected:
}
gfxFontFamily *mFamily;
private:
gfxFontEntry(const gfxFontEntry&);
gfxFontEntry& operator=(const gfxFontEntry&);
};
@ -925,6 +924,13 @@ public:
return mFontEntry->HasCharacter(ch);
}
PRUint16 GetUVSGlyph(PRUint32 aCh, PRUint32 aVS) {
if (!mIsValid) {
return 0;
}
return mFontEntry->GetUVSGlyph(aCh, aVS);
}
// Default implementation simply calls mShaper->InitTextRun().
// Override if the font class wants to give special handling
// to shaper failure.

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

@ -350,6 +350,13 @@ struct AutoSwap_PRUint64 {
PRUint64 value;
};
struct AutoSwap_PRUint24 {
operator PRUint32() const { return value[0] << 16 | value[1] << 8 | value[2]; }
private:
AutoSwap_PRUint24() { }
PRUint8 value[3];
};
#pragma pack()
} // namespace mozilla
@ -453,13 +460,13 @@ public:
};
// for reading big-endian font data on either big or little-endian platforms
static inline PRUint16
ReadShortAt(const PRUint8 *aBuf, PRUint32 aIndex)
{
return (aBuf[aIndex] << 8) | aBuf[aIndex + 1];
}
static inline PRUint16
ReadShortAt16(const PRUint16 *aBuf, PRUint32 aIndex)
{
@ -467,33 +474,49 @@ public:
PRUint32 index = aIndex << 1;
return (buf[index] << 8) | buf[index+1];
}
static inline PRUint32
ReadUint24At(const PRUint8 *aBuf, PRUint32 aIndex)
{
return ((aBuf[aIndex] << 16) | (aBuf[aIndex + 1] << 8) |
(aBuf[aIndex + 2]));
}
static inline PRUint32
ReadLongAt(const PRUint8 *aBuf, PRUint32 aIndex)
{
return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) |
(aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
}
static nsresult
ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength,
gfxSparseBitSet& aCharacterMap);
static nsresult
ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength,
gfxSparseBitSet& aCharacterMap);
static nsresult
ReadCMAPTableFormat14(PRUint8 *aBuf, PRUint32 aLength,
PRUint8*& aTable);
static PRUint32
FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
PRUint32 *aTableOffset, PRBool *aSymbolEncoding);
PRUint32 *aTableOffset, PRUint32 *aUVSTableOffset,
PRBool *aSymbolEncoding);
static nsresult
ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
PRUint32& aUVSOffset,
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont);
static PRUint32
MapCharToGlyphFormat4(const PRUint8 *aBuf, PRUnichar aCh);
static PRUint16
MapUVSToGlyphFormat14(const PRUint8 *aBuf, PRUint32 aCh, PRUint32 aVS);
static PRUint32
MapCharToGlyph(PRUint8 *aBuf, PRUint32 aBufLength, PRUnichar aCh);
@ -553,6 +576,18 @@ public:
return (ch == 0x200D);
}
enum {
kUnicodeVS1 = 0xFE00,
kUnicodeVS16 = 0xFE0F,
kUnicodeVS17 = 0xE0100,
kUnicodeVS256 = 0xE01EF
};
static inline bool IsVarSelector(PRUint32 ch) {
return (ch >= kUnicodeVS1 && ch <= kUnicodeVS16) ||
(ch >= kUnicodeVS17 && ch <= kUnicodeVS256);
}
static inline bool IsInvalid(PRUint32 ch) {
return (ch == 0xFFFD);
}

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

@ -287,6 +287,7 @@ gfxDWriteFontEntry::ReadCMAP()
rv = gfxFontUtils::ReadCMAP(tableData,
len,
mCharacterMap,
mUVSOffset,
isUnicode,
isSymbol);
}

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

@ -95,16 +95,6 @@ static const char *sCJKLangGroup[] = {
* FontEntry
*/
FontEntry::FontEntry(const FontEntry& aFontEntry) :
gfxFontEntry(aFontEntry)
{
mFTFace = aFontEntry.mFTFace;
if (aFontEntry.mFontFace)
mFontFace = cairo_font_face_reference(aFontEntry.mFontFace);
else
mFontFace = nsnull;
}
FontEntry::~FontEntry()
{
// Do nothing for mFTFace here since FTFontDestroyFunc is called by cairo.
@ -273,7 +263,7 @@ FontEntry::ReadCMAP()
PRPackedBool unicodeFont;
PRPackedBool symbolFont;
return gfxFontUtils::ReadCMAP(buf, len, mCharacterMap,
return gfxFontUtils::ReadCMAP(buf, len, mCharacterMap, mUVSOffset,
unicodeFont, symbolFont);
}

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

@ -100,6 +100,55 @@ PRBool gfxFontEntry::TestCharacterMap(PRUint32 aCh)
}
nsresult gfxFontEntry::InitializeUVSMap()
{
// mUVSOffset will not be initialized
// until cmap is initialized.
if (!mCmapInitialized) {
ReadCMAP();
}
if (!mUVSOffset) {
return NS_ERROR_FAILURE;
}
if (!mUVSData) {
const PRUint32 kCmapTag = TRUETYPE_TAG('c','m','a','p');
nsAutoTArray<PRUint8,16384> buffer;
if (GetFontTable(kCmapTag, buffer) != NS_OK) {
mUVSOffset = 0; // don't bother to read the table again
return NS_ERROR_FAILURE;
}
PRUint8* uvsData;
nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
buffer.Elements() + mUVSOffset,
buffer.Length() - mUVSOffset,
uvsData);
if (NS_FAILED(rv)) {
mUVSOffset = 0; // don't bother to read the table again
return rv;
}
mUVSData = uvsData;
}
return NS_OK;
}
PRUint16 gfxFontEntry::GetUVSGlyph(PRUint32 aCh, PRUint32 aVS)
{
InitializeUVSMap();
if (mUVSData) {
return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData, aCh, aVS);
}
return 0;
}
nsresult gfxFontEntry::ReadCMAP()
{
mCmapInitialized = PR_TRUE;
@ -2001,6 +2050,18 @@ gfxFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh, PRUint32 aNextCh,
}
}
// if this character is a variation selector,
// use the previous font regardless of whether it supports VS or not.
// otherwise the text run will be divided.
if (gfxFontUtils::IsVarSelector(aCh)) {
if (aPrevMatchedFont) {
selectedFont = aPrevMatchedFont;
return selectedFont.forget();
}
// VS alone. it's meaningless to search different fonts
return nsnull;
}
// 1. check fonts in the font group
for (PRUint32 i = 0; i < FontListLength(); i++) {
nsRefPtr<gfxFont> font = GetFontAt(i);

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

@ -359,29 +359,124 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBit
return NS_OK;
}
nsresult
gfxFontUtils::ReadCMAPTableFormat14(PRUint8 *aBuf, PRUint32 aLength,
PRUint8*& aTable)
{
enum {
OffsetFormat = 0,
OffsetTableLength = 2,
OffsetNumVarSelectorRecords = 6,
OffsetVarSelectorRecords = 10,
SizeOfVarSelectorRecord = 11,
VSRecOffsetVarSelector = 0,
VSRecOffsetDefUVSOffset = 3,
VSRecOffsetNonDefUVSOffset = 7,
SizeOfDefUVSTable = 4,
DefUVSOffsetStartUnicodeValue = 0,
DefUVSOffsetAdditionalCount = 3,
SizeOfNonDefUVSTable = 5,
NonDefUVSOffsetUnicodeValue = 0,
NonDefUVSOffsetGlyphID = 3
};
NS_ENSURE_TRUE(aLength >= OffsetVarSelectorRecords,
NS_ERROR_GFX_CMAP_MALFORMED);
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 14,
NS_ERROR_GFX_CMAP_MALFORMED);
PRUint32 tablelen = ReadLongAt(aBuf, OffsetTableLength);
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
NS_ENSURE_TRUE(tablelen >= OffsetVarSelectorRecords,
NS_ERROR_GFX_CMAP_MALFORMED);
const PRUint32 numVarSelectorRecords = ReadLongAt(aBuf, OffsetNumVarSelectorRecords);
NS_ENSURE_TRUE((tablelen - OffsetVarSelectorRecords) /
SizeOfVarSelectorRecord >= numVarSelectorRecords,
NS_ERROR_GFX_CMAP_MALFORMED);
const PRUint8 *records = aBuf + OffsetVarSelectorRecords;
for (PRUint32 i = 0; i < numVarSelectorRecords;
i++, records += SizeOfVarSelectorRecord) {
const PRUint32 varSelector = ReadUint24At(records, VSRecOffsetVarSelector);
const PRUint32 defUVSOffset = ReadLongAt(records, VSRecOffsetDefUVSOffset);
const PRUint32 nonDefUVSOffset = ReadLongAt(records, VSRecOffsetNonDefUVSOffset);
NS_ENSURE_TRUE(varSelector <= CMAP_MAX_CODEPOINT &&
defUVSOffset <= tablelen - 4 &&
nonDefUVSOffset <= tablelen - 4,
NS_ERROR_GFX_CMAP_MALFORMED);
if (defUVSOffset) {
const PRUint32 numUnicodeValueRanges = ReadLongAt(aBuf, defUVSOffset);
NS_ENSURE_TRUE((tablelen - defUVSOffset) /
SizeOfDefUVSTable >= numUnicodeValueRanges,
NS_ERROR_GFX_CMAP_MALFORMED);
const PRUint8 *tables = aBuf + defUVSOffset + 4;
PRUint32 prevEndUnicode = 0;
for (PRUint32 j = 0; j < numUnicodeValueRanges; j++, tables += SizeOfDefUVSTable) {
const PRUint32 startUnicode = ReadUint24At(tables, DefUVSOffsetStartUnicodeValue);
const PRUint32 endUnicode = startUnicode + tables[DefUVSOffsetAdditionalCount];
NS_ENSURE_TRUE((prevEndUnicode < startUnicode || j == 0) &&
endUnicode <= CMAP_MAX_CODEPOINT,
NS_ERROR_GFX_CMAP_MALFORMED);
prevEndUnicode = endUnicode;
}
}
if (nonDefUVSOffset) {
const PRUint32 numUVSMappings = ReadLongAt(aBuf, nonDefUVSOffset);
NS_ENSURE_TRUE((tablelen - nonDefUVSOffset) /
SizeOfNonDefUVSTable >= numUVSMappings,
NS_ERROR_GFX_CMAP_MALFORMED);
const PRUint8 *tables = aBuf + nonDefUVSOffset + 4;
PRUint32 prevUnicode = 0;
for (PRUint32 j = 0; j < numUVSMappings; j++, tables += SizeOfNonDefUVSTable) {
const PRUint32 unicodeValue = ReadUint24At(tables, NonDefUVSOffsetUnicodeValue);
const PRUint16 glyphID = ReadShortAt(tables, NonDefUVSOffsetGlyphID);
NS_ENSURE_TRUE((prevUnicode < unicodeValue || j == 0) &&
unicodeValue <= CMAP_MAX_CODEPOINT,
NS_ERROR_GFX_CMAP_MALFORMED);
prevUnicode = unicodeValue;
}
}
}
aTable = new PRUint8[tablelen];
memcpy(aTable, aBuf, tablelen);
return NS_OK;
}
// Windows requires fonts to have a format-4 cmap with a Microsoft ID (3). On the Mac, fonts either have
// a format-4 cmap with Microsoft platform/encoding id or they have one with a platformID == Unicode (0)
// For fonts with two format-4 tables, the first one (Unicode platform) is preferred on the Mac.
#if defined(XP_MACOSX)
#define acceptablePlatform(p) ((p) == PLATFORM_ID_UNICODE || (p) == PLATFORM_ID_MICROSOFT)
#define acceptableFormat4(p,e,k) ( ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft && (k) != 4) || \
((p) == PLATFORM_ID_UNICODE) )
#define isSymbol(p,e) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDSymbol)
#define acceptableFormat4(p,e,k) (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft && !(k)) || \
((p) == PLATFORM_ID_UNICODE))
#define acceptableUCS4Encoding(p, e, k) \
(((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform) && (k) != 12 || \
((p) == PLATFORM_ID_UNICODE && \
((e) == EncodingIDDefaultForUnicodePlatform || (e) >= EncodingIDUCS4ForUnicodePlatform)))
#else
#define acceptablePlatform(p) ((p) == PLATFORM_ID_MICROSOFT)
#define acceptableFormat4(p,e,k) ((e) == EncodingIDMicrosoft)
#define isSymbol(p,e) ((e) == EncodingIDSymbol)
#define acceptableFormat4(p,e,k) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft)
#define acceptableUCS4Encoding(p, e, k) \
((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform)
#endif
#define acceptableUCS4Encoding(p, e) \
((platformID == PLATFORM_ID_MICROSOFT && encodingID == EncodingIDUCS4ForMicrosoftPlatform) || \
(platformID == PLATFORM_ID_UNICODE && \
(encodingID == EncodingIDDefaultForUnicodePlatform || encodingID >= EncodingIDUCS4ForUnicodePlatform)))
#define acceptablePlatform(p) ((p) == PLATFORM_ID_UNICODE || (p) == PLATFORM_ID_MICROSOFT)
#define isSymbol(p,e) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDSymbol)
#define isUVSEncoding(p, e) ((p) == PLATFORM_ID_UNICODE && (e) == EncodingIDUVSForUnicodePlatform)
PRUint32
gfxFontUtils::FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
PRUint32 *aTableOffset, PRBool *aSymbolEncoding)
PRUint32 *aTableOffset, PRUint32 *aUVSTableOffset,
PRBool *aSymbolEncoding)
{
enum {
OffsetVersion = 0,
@ -400,9 +495,14 @@ gfxFontUtils::FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
EncodingIDMicrosoft = 1,
EncodingIDDefaultForUnicodePlatform = 0,
EncodingIDUCS4ForUnicodePlatform = 3,
EncodingIDUVSForUnicodePlatform = 5,
EncodingIDUCS4ForMicrosoftPlatform = 10
};
if (aUVSTableOffset) {
*aUVSTableOffset = nsnull;
}
// PRUint16 version = ReadShortAt(aBuf, OffsetVersion); // Unused: self-documenting.
PRUint16 numTables = ReadShortAt(aBuf, OffsetNumTables);
@ -433,11 +533,18 @@ gfxFontUtils::FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
keepFormat = format;
*aTableOffset = offset;
*aSymbolEncoding = PR_FALSE;
} else if (format == 12 && acceptableUCS4Encoding(platformID, encodingID)) {
} else if (format == 12 && acceptableUCS4Encoding(platformID, encodingID, keepFormat)) {
keepFormat = format;
*aTableOffset = offset;
*aSymbolEncoding = PR_FALSE;
break; // we don't want to try anything else when this format is available.
if (platformID > PLATFORM_ID_UNICODE || !aUVSTableOffset || *aUVSTableOffset) {
break; // we don't want to try anything else when this format is available.
}
} else if (format == 14 && isUVSEncoding(platformID, encodingID) && aUVSTableOffset) {
*aUVSTableOffset = offset;
if (keepFormat == 12) {
break;
}
}
}
@ -445,12 +552,13 @@ gfxFontUtils::FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
}
nsresult
gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
PRUint32& aUVSOffset,
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont)
{
PRUint32 offset;
PRBool symbol;
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset, &symbol);
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset, &aUVSOffset, &symbol);
if (format == 4) {
if (symbol) {
@ -488,6 +596,31 @@ typedef struct {
AutoSwap_PRUint16 arrays[1];
} Format4Cmap;
typedef struct {
AutoSwap_PRUint16 format;
AutoSwap_PRUint32 length;
AutoSwap_PRUint32 numVarSelectorRecords;
typedef struct {
AutoSwap_PRUint24 varSelector;
AutoSwap_PRUint32 defaultUVSOffset;
AutoSwap_PRUint32 nonDefaultUVSOffset;
} VarSelectorRecord;
VarSelectorRecord varSelectorRecords[1];
} Format14Cmap;
typedef struct {
AutoSwap_PRUint32 numUVSMappings;
typedef struct {
AutoSwap_PRUint24 unicodeValue;
AutoSwap_PRUint16 glyphID;
} UVSMapping;
UVSMapping uvsMappings[1];
} NonDefUVSTable;
#pragma pack()
PRUint32
@ -551,12 +684,60 @@ gfxFontUtils::MapCharToGlyphFormat4(const PRUint8 *aBuf, PRUnichar aCh)
return 0;
}
PRUint16
gfxFontUtils::MapUVSToGlyphFormat14(const PRUint8 *aBuf, PRUint32 aCh, PRUint32 aVS)
{
const Format14Cmap *cmap14 = reinterpret_cast<const Format14Cmap*>(aBuf);
// binary search in varSelectorRecords
PRUint32 min = 0;
PRUint32 max = cmap14->numVarSelectorRecords;
PRUint32 nonDefUVSOffset = 0;
while (min < max) {
PRUint32 index = (min + max) >> 1;
PRUint32 varSelector = cmap14->varSelectorRecords[index].varSelector;
if (aVS == varSelector) {
nonDefUVSOffset = cmap14->varSelectorRecords[index].nonDefaultUVSOffset;
break;
}
if (aVS < varSelector) {
max = index;
} else {
min = index + 1;
}
}
if (!nonDefUVSOffset) {
return 0;
}
const NonDefUVSTable *table = reinterpret_cast<const NonDefUVSTable*>
(aBuf + nonDefUVSOffset);
// binary search in uvsMappings
min = 0;
max = table->numUVSMappings;
while (min < max) {
PRUint32 index = (min + max) >> 1;
PRUint32 unicodeValue = table->uvsMappings[index].unicodeValue;
if (aCh == unicodeValue) {
return table->uvsMappings[index].glyphID;
}
if (aCh < unicodeValue) {
max = index;
} else {
min = index + 1;
}
}
return 0;
}
PRUint32
gfxFontUtils::MapCharToGlyph(PRUint8 *aBuf, PRUint32 aBufLength, PRUnichar aCh)
{
PRUint32 offset;
PRBool symbol;
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset, &symbol);
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset, nsnull, &symbol);
if (format == 4)
return MapCharToGlyphFormat4(aBuf + offset, aCh);

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

@ -226,7 +226,7 @@ GDIFontEntry::ReadCMAP()
PRPackedBool unicodeFont = PR_FALSE, symbolFont = PR_FALSE;
nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
mCharacterMap, unicodeFont, symbolFont);
mCharacterMap, mUVSOffset, unicodeFont, symbolFont);
mUnicodeFont = unicodeFont;
mSymbolFont = symbolFont;

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

@ -214,7 +214,7 @@ MacOSFontEntry::ReadCMAP()
PRPackedBool unicodeFont, symbolFont; // currently ignored
nsresult rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
mCharacterMap, unicodeFont, symbolFont);
mCharacterMap, mUVSOffset, unicodeFont, symbolFont);
if (NS_FAILED(rv)) {
mCharacterMap.reset();

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

@ -1087,7 +1087,7 @@ gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aStri
ch = SURROGATE_TO_UCS4(ch, aString[i+1]);
surrogatePair = PR_TRUE;
}
if (i > 0 && gc->Get(aString[i]) == nsIUGenCategory::kMark) {
if (i > 0 && gc->Get(ch) == nsIUGenCategory::kMark) {
gfxTextRun::CompressedGlyph g;
aTextRun->SetGlyphs(i, g.SetComplex(PR_FALSE, PR_TRUE, 0), nsnull);
}

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

@ -76,14 +76,14 @@ public:
UniscribeItem(gfxContext *aContext, HDC aDC,
gfxUniscribeShaper *aShaper,
const PRUnichar *aString, PRUint32 aLength,
SCRIPT_ITEM *aItem) :
SCRIPT_ITEM *aItem, PRUint32 aIVS) :
mContext(aContext), mDC(aDC),
mShaper(aShaper),
mItemString(aString), mItemLength(aLength),
mAlternativeString(nsnull), mScriptItem(aItem),
mScript(aItem->a.eScript),
mNumGlyphs(0), mMaxGlyphs(ESTIMATE_MAX_GLYPHS(aLength)),
mFontSelected(PR_FALSE)
mFontSelected(PR_FALSE), mIVS(aIVS)
{
NS_ASSERTION(mMaxGlyphs < 65535, "UniscribeItem is too big, ScriptShape() will fail!");
}
@ -166,6 +166,20 @@ public:
continue;
}
// Prior to Windows 7, Uniscribe didn't support Ideographic Variation
// Selectors. Replace the UVS glyph manually.
if (mIVS) {
PRUint32 lastChar = str[mItemLength - 1];
if (NS_IS_LOW_SURROGATE(lastChar)
&& NS_IS_HIGH_SURROGATE(str[mItemLength - 2])) {
lastChar = SURROGATE_TO_UCS4(str[mItemLength - 2], lastChar);
}
PRUint16 glyphId = mShaper->GetFont()->GetUVSGlyph(lastChar, mIVS);
if (glyphId) {
mGlyphs[mNumGlyphs - 1] = glyphId;
}
}
return rv;
}
}
@ -375,6 +389,7 @@ private:
int mMaxGlyphs;
int mNumGlyphs;
PRUint32 mIVS;
PRPackedBool mFontSelected;
};
@ -554,11 +569,34 @@ gfxUniscribeShaper::InitTextRun(gfxContext *aContext,
int numItems = us.Itemize();
SaveDC(aDC);
PRUint32 ivs = 0;
for (int i = 0; i < numItems; ++i) {
int iCharPos = us.ScriptItem(i)->iCharPos;
int iCharPosNext = us.ScriptItem(i+1)->iCharPos;
if (ivs) {
iCharPos += 2;
if (iCharPos >= iCharPosNext) {
ivs = 0;
continue;
}
}
if (i+1 < numItems && aRunStart + iCharPosNext <= aRunLength - 2
&& aString[aRunStart + iCharPosNext] == H_SURROGATE(kUnicodeVS17)
&& PRUint32(aString[aRunStart + iCharPosNext + 1]) - L_SURROGATE(kUnicodeVS17)
<= L_SURROGATE(kUnicodeVS256) - L_SURROGATE(kUnicodeVS17)) {
ivs = SURROGATE_TO_UCS4(aString[aRunStart + iCharPosNext],
aString[aRunStart + iCharPosNext + 1]);
} else {
ivs = 0;
}
UniscribeItem item(aContext, aDC, this,
aString + aRunStart + us.ScriptItem(i)->iCharPos,
us.ScriptItem(i+1)->iCharPos - us.ScriptItem(i)->iCharPos,
us.ScriptItem(i));
aString + aRunStart + iCharPos,
iCharPosNext - iCharPos,
us.ScriptItem(i), ivs);
if (!item.AllocateBuffers()) {
result = PR_FALSE;
break;

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

@ -76,6 +76,11 @@ public:
private:
SCRIPT_CACHE mScriptCache;
enum {
kUnicodeVS17 = gfxFontUtils::kUnicodeVS17,
kUnicodeVS256 = gfxFontUtils::kUnicodeVS256
};
};
#endif /* GFX_UNISCRIBESHAPER_H */