зеркало из https://github.com/mozilla/pjs.git
Bug 380484. Work around ATSUI's 32k pixel limitation; when creating textruns, split the textrun up into smaller pieces if necessary before we pass it to ATSUI. r=vlad
This commit is contained in:
Родитель
1229e4399d
Коммит
45323b4ff4
|
@ -128,8 +128,11 @@ protected:
|
||||||
const nsACString& aGenericName,
|
const nsACString& aGenericName,
|
||||||
void *closure);
|
void *closure);
|
||||||
|
|
||||||
void InitTextRun(gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength,
|
PRUint32 GuessMaximumStringLength();
|
||||||
PRBool aWrapped);
|
|
||||||
|
/** Returns true for success */
|
||||||
|
PRBool InitTextRun(gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength,
|
||||||
|
PRBool aWrapped, PRUint32 aSegmentStart, PRUint32 aSegmentLength);
|
||||||
|
|
||||||
ATSUFontFallbacks mFallbacks;
|
ATSUFontFallbacks mFallbacks;
|
||||||
};
|
};
|
||||||
|
|
|
@ -422,21 +422,6 @@ SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString)
|
||||||
UCDisposeTextBreakLocator(&locator);
|
UCDisposeTextBreakLocator(&locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
gfxAtsuiFontGroup::MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
|
|
||||||
PRBool aWrapped, gfxTextRun *aTextRun)
|
|
||||||
{
|
|
||||||
// NS_ASSERTION(!(aParams->mFlags & TEXT_NEED_BOUNDING_BOX),
|
|
||||||
// "Glyph extents not yet supported");
|
|
||||||
const PRUnichar *realString = aString + (aWrapped ? 1 : 0);
|
|
||||||
aTextRun->RecordSurrogates(realString);
|
|
||||||
if (!(aTextRun->GetFlags() & TEXT_IS_8BIT)) {
|
|
||||||
SetupClusterBoundaries(aTextRun, realString);
|
|
||||||
}
|
|
||||||
|
|
||||||
InitTextRun(aTextRun, aString, aLength, aWrapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define UNICODE_LRO 0x202d
|
#define UNICODE_LRO 0x202d
|
||||||
#define UNICODE_RLO 0x202e
|
#define UNICODE_RLO 0x202e
|
||||||
#define UNICODE_PDF 0x202c
|
#define UNICODE_PDF 0x202c
|
||||||
|
@ -448,6 +433,70 @@ AppendDirectionalIndicator(PRUint32 aFlags, nsAString& aString)
|
||||||
aString.Append(overrides[(aFlags & gfxTextRunFactory::TEXT_IS_RTL) != 0]);
|
aString.Append(overrides[(aFlags & gfxTextRunFactory::TEXT_IS_RTL) != 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a textrun and an offset into that textrun, we need to choose a length
|
||||||
|
* for the substring of the textrun that we should analyze next. The length
|
||||||
|
* should be <= aMaxLength if possible. It must always end at a cluster
|
||||||
|
* boundary and it should end at the end of the textrun or at the
|
||||||
|
* boundary of a space if possible.
|
||||||
|
*/
|
||||||
|
static PRUint32
|
||||||
|
FindTextRunSegmentLength(gfxTextRun *aTextRun, PRUint32 aOffset, PRUint32 aMaxLength)
|
||||||
|
{
|
||||||
|
if (aOffset + aMaxLength >= aTextRun->GetLength()) {
|
||||||
|
// The remaining part of the textrun fits within the max length,
|
||||||
|
// so just use it.
|
||||||
|
return aTextRun->GetLength() - aOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to end the segment before or after a space, since spaces don't kern
|
||||||
|
// or ligate.
|
||||||
|
PRUint32 end;
|
||||||
|
for (end = aOffset + aMaxLength; end > aOffset; --end) {
|
||||||
|
if (aTextRun->IsClusterStart(end) &&
|
||||||
|
(aTextRun->GetChar(end) == ' ' || aTextRun->GetChar(end - 1) == ' '))
|
||||||
|
return end - aOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to end the segment at the last cluster boundary.
|
||||||
|
for (end = aOffset + aMaxLength; end > aOffset; --end) {
|
||||||
|
if (aTextRun->IsClusterStart(end))
|
||||||
|
return end - aOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I guess we just have to return a segment that's the entire cluster
|
||||||
|
// starting at aOffset.
|
||||||
|
for (end = aOffset + 1; end < aTextRun->GetLength(); ++end) {
|
||||||
|
if (aTextRun->IsClusterStart(end))
|
||||||
|
return end - aOffset;
|
||||||
|
}
|
||||||
|
return aTextRun->GetLength() - aOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRUint32
|
||||||
|
gfxAtsuiFontGroup::GuessMaximumStringLength()
|
||||||
|
{
|
||||||
|
gfxFloat maxAdvance = GetFontAt(0)->GetMetrics().maxAdvance;
|
||||||
|
// ATSUI can't handle offsets of more than 32K pixels
|
||||||
|
PRUint32 chars = 0x7FFF/PRUint32(maxAdvance);
|
||||||
|
return PR_MAX(1, chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ATSUI can't handle more than 32K pixels of text. We can easily have
|
||||||
|
* textruns longer than that. Our strategy here is to divide the textrun up
|
||||||
|
* into pieces each of which is less than 32K pixels wide. We pick a number
|
||||||
|
* of characters 'maxLen' such that the first font's max-advance times that
|
||||||
|
* number of characters is less than 32K pixels; then we try glyph conversion
|
||||||
|
* of the string broken up into chunks each with no more than 'maxLen'
|
||||||
|
* characters. That could fail (e.g. if fallback fonts are used); if it does,
|
||||||
|
* we retry with a smaller maxLen. When breaking up the string into chunks
|
||||||
|
* we prefer to break at space boundaries because spaces don't kern or ligate
|
||||||
|
* with other characters, usually. We insist on breaking at cluster boundaries.
|
||||||
|
* If the font size is incredibly huge and/or clusters are very large, this
|
||||||
|
* could mean that we actually put more than 'maxLen' characters in a chunk.
|
||||||
|
*/
|
||||||
|
|
||||||
gfxTextRun *
|
gfxTextRun *
|
||||||
gfxAtsuiFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
|
gfxAtsuiFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
|
||||||
const Parameters *aParams, PRUint32 aFlags)
|
const Parameters *aParams, PRUint32 aFlags)
|
||||||
|
@ -456,14 +505,33 @@ gfxAtsuiFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
|
||||||
if (!textRun)
|
if (!textRun)
|
||||||
return nsnull;
|
return nsnull;
|
||||||
|
|
||||||
|
textRun->RecordSurrogates(aString);
|
||||||
|
SetupClusterBoundaries(textRun, aString);
|
||||||
|
|
||||||
|
PRUint32 maxLen;
|
||||||
nsAutoString utf16;
|
nsAutoString utf16;
|
||||||
|
for (maxLen = GuessMaximumStringLength(); maxLen > 0; maxLen /= 2) {
|
||||||
|
PRUint32 start = 0;
|
||||||
|
while (start < aLength) {
|
||||||
|
PRUint32 len = FindTextRunSegmentLength(textRun, start, maxLen);
|
||||||
|
|
||||||
|
utf16.Truncate();
|
||||||
AppendDirectionalIndicator(aFlags, utf16);
|
AppendDirectionalIndicator(aFlags, utf16);
|
||||||
utf16.Append(aString, aLength);
|
utf16.Append(aString + start, len);
|
||||||
// Ensure that none of the whitespace in the run is considered "trailing"
|
// Ensure that none of the whitespace in the run is considered "trailing"
|
||||||
// by ATSUI's bidi algorithm
|
// by ATSUI's bidi algorithm
|
||||||
utf16.Append('.');
|
utf16.Append('.');
|
||||||
utf16.Append(UNICODE_PDF);
|
utf16.Append(UNICODE_PDF);
|
||||||
MakeTextRunInternal(utf16.get(), utf16.Length(), PR_TRUE, textRun);
|
if (!InitTextRun(textRun, utf16.get(), utf16.Length(), PR_TRUE,
|
||||||
|
start, len) && maxLen > 1)
|
||||||
|
break;
|
||||||
|
start += len;
|
||||||
|
}
|
||||||
|
if (start == aLength)
|
||||||
|
break;
|
||||||
|
textRun->ResetGlyphRuns();
|
||||||
|
}
|
||||||
|
|
||||||
return textRun;
|
return textRun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,9 +544,16 @@ gfxAtsuiFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
|
||||||
if (!textRun)
|
if (!textRun)
|
||||||
return nsnull;
|
return nsnull;
|
||||||
|
|
||||||
nsDependentCSubstring cString(reinterpret_cast<const char*>(aString),
|
PRUint32 maxLen;
|
||||||
reinterpret_cast<const char*>(aString + aLength));
|
|
||||||
nsAutoString utf16;
|
nsAutoString utf16;
|
||||||
|
for (maxLen = GuessMaximumStringLength(); maxLen > 0; maxLen /= 2) {
|
||||||
|
PRUint32 start = 0;
|
||||||
|
while (start < aLength) {
|
||||||
|
PRUint32 len = FindTextRunSegmentLength(textRun, start, maxLen);
|
||||||
|
|
||||||
|
nsDependentCSubstring cString(reinterpret_cast<const char*>(aString + start),
|
||||||
|
reinterpret_cast<const char*>(aString + start + len));
|
||||||
|
utf16.Truncate();
|
||||||
PRBool wrapBidi = (aFlags & TEXT_IS_RTL) != 0;
|
PRBool wrapBidi = (aFlags & TEXT_IS_RTL) != 0;
|
||||||
if (wrapBidi) {
|
if (wrapBidi) {
|
||||||
AppendDirectionalIndicator(aFlags, utf16);
|
AppendDirectionalIndicator(aFlags, utf16);
|
||||||
|
@ -488,7 +563,16 @@ gfxAtsuiFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
|
||||||
utf16.Append('.');
|
utf16.Append('.');
|
||||||
utf16.Append(UNICODE_PDF);
|
utf16.Append(UNICODE_PDF);
|
||||||
}
|
}
|
||||||
MakeTextRunInternal(utf16.get(), utf16.Length(), wrapBidi, textRun);
|
if (!InitTextRun(textRun, utf16.get(), utf16.Length(), wrapBidi,
|
||||||
|
start, len) && maxLen > 1)
|
||||||
|
break;
|
||||||
|
start += len;
|
||||||
|
}
|
||||||
|
if (start == aLength)
|
||||||
|
break;
|
||||||
|
textRun->ResetGlyphRuns();
|
||||||
|
}
|
||||||
|
|
||||||
return textRun;
|
return textRun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,6 +625,11 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ATSUI_SPECIAL_GLYPH_ID 0xFFFF
|
#define ATSUI_SPECIAL_GLYPH_ID 0xFFFF
|
||||||
|
/**
|
||||||
|
* This flag seems to be set on glyphs that have overrun the 32K pixel
|
||||||
|
* limit in ATSUI.
|
||||||
|
*/
|
||||||
|
#define ATSUI_OVERRUNNING_GLYPH_FLAG 0x100000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the advance in appunits of a run of ATSUI glyphs
|
* Calculate the advance in appunits of a run of ATSUI glyphs
|
||||||
|
@ -561,7 +650,8 @@ GetAdvanceAppUnits(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||||
static void
|
static void
|
||||||
SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||||
Fixed *aBaselineDeltas, PRUint32 aAppUnitsPerDevUnit,
|
Fixed *aBaselineDeltas, PRUint32 aAppUnitsPerDevUnit,
|
||||||
gfxTextRun *aRun, const PRPackedBool *aUnmatched,
|
gfxTextRun *aRun, PRUint32 aSegmentStart,
|
||||||
|
const PRPackedBool *aUnmatched,
|
||||||
const PRUnichar *aString)
|
const PRUnichar *aString)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(aGlyphCount > 0, "Must set at least one glyph");
|
NS_ASSERTION(aGlyphCount > 0, "Must set at least one glyph");
|
||||||
|
@ -593,7 +683,7 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||||
if (!allMatched) {
|
if (!allMatched) {
|
||||||
for (i = firstOffset; i <= lastOffset; ++i) {
|
for (i = firstOffset; i <= lastOffset; ++i) {
|
||||||
PRUint32 index = i/2;
|
PRUint32 index = i/2;
|
||||||
aRun->SetMissingGlyph(index, aString[index]);
|
aRun->SetMissingGlyph(aSegmentStart + index, aString[index]);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -605,9 +695,9 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||||
if (!inOrder) {
|
if (!inOrder) {
|
||||||
// Because the characters in this group were not in the textrun's
|
// Because the characters in this group were not in the textrun's
|
||||||
// required order, we must make the entire group an indivisible cluster
|
// required order, we must make the entire group an indivisible cluster
|
||||||
aRun->SetCharacterGlyph(index, g.SetClusterContinuation());
|
aRun->SetCharacterGlyph(aSegmentStart + index, g.SetClusterContinuation());
|
||||||
} else if (!aRun->GetCharacterGlyphs()[index].IsClusterContinuation()) {
|
} else if (!aRun->GetCharacterGlyphs()[index].IsClusterContinuation()) {
|
||||||
aRun->SetCharacterGlyph(index, g.SetLigatureContinuation());
|
aRun->SetCharacterGlyph(aSegmentStart + index, g.SetLigatureContinuation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,7 +709,7 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||||
(!aBaselineDeltas || aBaselineDeltas[displayGlyph - aGlyphs] == 0) &&
|
(!aBaselineDeltas || aBaselineDeltas[displayGlyph - aGlyphs] == 0) &&
|
||||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(displayGlyph->glyphID)) {
|
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(displayGlyph->glyphID)) {
|
||||||
aRun->SetCharacterGlyph(index, g.SetSimpleGlyph(advance, displayGlyph->glyphID));
|
aRun->SetCharacterGlyph(aSegmentStart + index, g.SetSimpleGlyph(advance, displayGlyph->glyphID));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,20 +737,24 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||||
}
|
}
|
||||||
if (detailedGlyphs.Length() == 0) {
|
if (detailedGlyphs.Length() == 0) {
|
||||||
NS_WARNING("No glyphs visible at all!");
|
NS_WARNING("No glyphs visible at all!");
|
||||||
aRun->SetCharacterGlyph(index, g.SetMissing());
|
aRun->SetCharacterGlyph(aSegmentStart + index, g.SetMissing());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
detailedGlyphs[detailedGlyphs.Length() - 1].mIsLastGlyph = PR_TRUE;
|
detailedGlyphs[detailedGlyphs.Length() - 1].mIsLastGlyph = PR_TRUE;
|
||||||
detailedGlyphs[detailedGlyphs.Length() - 1].mAdvance =
|
detailedGlyphs[detailedGlyphs.Length() - 1].mAdvance =
|
||||||
GetAdvanceAppUnits(advanceStart, aGlyphs + aGlyphCount - advanceStart, aAppUnitsPerDevUnit);
|
GetAdvanceAppUnits(advanceStart, aGlyphs + aGlyphCount - advanceStart, aAppUnitsPerDevUnit);
|
||||||
aRun->SetDetailedGlyphs(index, detailedGlyphs.Elements(), detailedGlyphs.Length());
|
aRun->SetDetailedGlyphs(aSegmentStart + index, detailedGlyphs.Elements(), detailedGlyphs.Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/**
|
||||||
|
* Returns true if there are overrunning glyphs
|
||||||
|
*/
|
||||||
|
static PRBool
|
||||||
PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||||
const PRUnichar *aString, PRBool aWrapped,
|
const PRUnichar *aString, PRBool aWrapped,
|
||||||
const PRPackedBool *aUnmatched)
|
const PRPackedBool *aUnmatched,
|
||||||
|
PRUint32 aSegmentStart, PRUint32 aSegmentLength)
|
||||||
{
|
{
|
||||||
// AutoLayoutDataArrayPtr advanceDeltasArray(aLine, kATSUDirectDataAdvanceDeltaFixedArray);
|
// AutoLayoutDataArrayPtr advanceDeltasArray(aLine, kATSUDirectDataAdvanceDeltaFixedArray);
|
||||||
// Fixed *advanceDeltas = NS_STATIC_CAST(Fixed *, advanceDeltasArray.mArray);
|
// Fixed *advanceDeltas = NS_STATIC_CAST(Fixed *, advanceDeltasArray.mArray);
|
||||||
|
@ -672,7 +766,7 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||||
PRUint32 numGlyphs = glyphRecordsArray.mItemCount;
|
PRUint32 numGlyphs = glyphRecordsArray.mItemCount;
|
||||||
if (numGlyphs == 0 || !glyphRecordsArray.mArray) {
|
if (numGlyphs == 0 || !glyphRecordsArray.mArray) {
|
||||||
NS_WARNING("Failed to retrieve key glyph data");
|
NS_WARNING("Failed to retrieve key glyph data");
|
||||||
return;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
ATSLayoutRecord *glyphRecords = NS_STATIC_CAST(ATSLayoutRecord *, glyphRecordsArray.mArray);
|
ATSLayoutRecord *glyphRecords = NS_STATIC_CAST(ATSLayoutRecord *, glyphRecordsArray.mArray);
|
||||||
NS_ASSERTION(!baselineDeltas || baselineDeltasArray.mItemCount == numGlyphs,
|
NS_ASSERTION(!baselineDeltas || baselineDeltasArray.mItemCount == numGlyphs,
|
||||||
|
@ -681,7 +775,7 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||||
"Last glyph should be a terminator glyph");
|
"Last glyph should be a terminator glyph");
|
||||||
--numGlyphs;
|
--numGlyphs;
|
||||||
if (numGlyphs == 0)
|
if (numGlyphs == 0)
|
||||||
return;
|
return PR_FALSE;
|
||||||
|
|
||||||
PRUint32 appUnitsPerDevUnit = aRun->GetAppUnitsPerDevUnit();
|
PRUint32 appUnitsPerDevUnit = aRun->GetAppUnitsPerDevUnit();
|
||||||
PRBool isRTL = aRun->IsRightToLeft();
|
PRBool isRTL = aRun->IsRightToLeft();
|
||||||
|
@ -690,18 +784,19 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||||
// The glyph array includes a glyph for the artificial trailing
|
// The glyph array includes a glyph for the artificial trailing
|
||||||
// non-whitespace character. Strip that glyph from the array now.
|
// non-whitespace character. Strip that glyph from the array now.
|
||||||
if (isRTL) {
|
if (isRTL) {
|
||||||
NS_ASSERTION(glyphRecords[0].originalOffset == aRun->GetLength()*2,
|
NS_ASSERTION(glyphRecords[0].originalOffset == aSegmentLength*2,
|
||||||
"Couldn't find glyph for trailing marker");
|
"Couldn't find glyph for trailing marker");
|
||||||
glyphRecords++;
|
glyphRecords++;
|
||||||
} else {
|
} else {
|
||||||
NS_ASSERTION(glyphRecords[numGlyphs - 1].originalOffset == aRun->GetLength()*2,
|
NS_ASSERTION(glyphRecords[numGlyphs - 1].originalOffset == aSegmentLength*2,
|
||||||
"Couldn't find glyph for trailing marker");
|
"Couldn't find glyph for trailing marker");
|
||||||
}
|
}
|
||||||
--numGlyphs;
|
--numGlyphs;
|
||||||
if (numGlyphs == 0)
|
if (numGlyphs == 0)
|
||||||
return;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRUint32 allFlags = 0;
|
||||||
// Now process the glyphs, which should basically be in
|
// Now process the glyphs, which should basically be in
|
||||||
// the textrun's desired order, so process them in textrun order
|
// the textrun's desired order, so process them in textrun order
|
||||||
PRInt32 direction = PRInt32(aRun->GetDirection());
|
PRInt32 direction = PRInt32(aRun->GetDirection());
|
||||||
|
@ -713,6 +808,7 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||||
while (glyphCount < numGlyphs) {
|
while (glyphCount < numGlyphs) {
|
||||||
ATSLayoutRecord *glyph = &glyphRecords[glyphIndex + direction*glyphCount];
|
ATSLayoutRecord *glyph = &glyphRecords[glyphIndex + direction*glyphCount];
|
||||||
PRUint32 glyphOffset = glyph->originalOffset;
|
PRUint32 glyphOffset = glyph->originalOffset;
|
||||||
|
allFlags |= glyph->flags;
|
||||||
// Always add the current glyph to the group if it's for the same
|
// Always add the current glyph to the group if it's for the same
|
||||||
// character as a character whose glyph is already in the group,
|
// character as a character whose glyph is already in the group,
|
||||||
// or an earlier character. The latter can happen because ATSUI
|
// or an earlier character. The latter can happen because ATSUI
|
||||||
|
@ -722,7 +818,7 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||||
// In this case we need to make sure the glyph for the consonant
|
// In this case we need to make sure the glyph for the consonant
|
||||||
// is added to the group containing the vowel.
|
// is added to the group containing the vowel.
|
||||||
if (lastOffset < glyphOffset) {
|
if (lastOffset < glyphOffset) {
|
||||||
if (!aRun->IsClusterStart(glyphOffset/2)) {
|
if (!aRun->IsClusterStart(aSegmentStart + glyphOffset/2)) {
|
||||||
// next character is a cluster continuation,
|
// next character is a cluster continuation,
|
||||||
// add it to the current group
|
// add it to the current group
|
||||||
lastOffset = glyphOffset;
|
lastOffset = glyphOffset;
|
||||||
|
@ -747,13 +843,13 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||||
SetGlyphsForCharacterGroup(glyphRecords + numGlyphs - glyphCount,
|
SetGlyphsForCharacterGroup(glyphRecords + numGlyphs - glyphCount,
|
||||||
glyphCount,
|
glyphCount,
|
||||||
baselineDeltas ? baselineDeltas + numGlyphs - glyphCount : nsnull,
|
baselineDeltas ? baselineDeltas + numGlyphs - glyphCount : nsnull,
|
||||||
appUnitsPerDevUnit, aRun, aUnmatched,
|
appUnitsPerDevUnit, aRun, aSegmentStart,
|
||||||
aString);
|
aUnmatched, aString);
|
||||||
} else {
|
} else {
|
||||||
SetGlyphsForCharacterGroup(glyphRecords,
|
SetGlyphsForCharacterGroup(glyphRecords,
|
||||||
glyphCount, baselineDeltas,
|
glyphCount, baselineDeltas,
|
||||||
appUnitsPerDevUnit, aRun, aUnmatched,
|
appUnitsPerDevUnit, aRun, aSegmentStart,
|
||||||
aString);
|
aUnmatched, aString);
|
||||||
glyphRecords += glyphCount;
|
glyphRecords += glyphCount;
|
||||||
if (baselineDeltas) {
|
if (baselineDeltas) {
|
||||||
baselineDeltas += glyphCount;
|
baselineDeltas += glyphCount;
|
||||||
|
@ -761,17 +857,23 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||||
}
|
}
|
||||||
numGlyphs -= glyphCount;
|
numGlyphs -= glyphCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (allFlags & ATSUI_OVERRUNNING_GLYPH_FLAG) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PostLayoutCallbackClosure {
|
struct PostLayoutCallbackClosure {
|
||||||
gfxTextRun *mTextRun;
|
gfxTextRun *mTextRun;
|
||||||
const PRUnichar *mString;
|
const PRUnichar *mString;
|
||||||
// This is true when we inserted an artifical trailing character at the
|
|
||||||
// end of the string when computing the ATSUI layout.
|
|
||||||
PRPackedBool mWrapped;
|
|
||||||
// Either null or an array of stringlength booleans set to true for
|
// Either null or an array of stringlength booleans set to true for
|
||||||
// each character that did not match any fonts
|
// each character that did not match any fonts
|
||||||
nsAutoArrayPtr<PRPackedBool> mUnmatchedChars;
|
nsAutoArrayPtr<PRPackedBool> mUnmatchedChars;
|
||||||
|
PRUint32 mSegmentStart;
|
||||||
|
PRUint32 mSegmentLength;
|
||||||
|
// This is true when we inserted an artifical trailing character at the
|
||||||
|
// end of the string when computing the ATSUI layout.
|
||||||
|
PRPackedBool mWrapped;
|
||||||
|
// The callback *sets* this to indicate whether there were overrunning glyphs
|
||||||
|
PRPackedBool mOverrunningGlyphs;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is really disgusting, but the ATSUI refCon thing is also disgusting
|
// This is really disgusting, but the ATSUI refCon thing is also disgusting
|
||||||
|
@ -784,17 +886,21 @@ PostLayoutOperationCallback(ATSULayoutOperationSelector iCurrentOperation,
|
||||||
void *iOperationCallbackParameterPtr,
|
void *iOperationCallbackParameterPtr,
|
||||||
ATSULayoutOperationCallbackStatus *oCallbackStatus)
|
ATSULayoutOperationCallbackStatus *oCallbackStatus)
|
||||||
{
|
{
|
||||||
|
gCallbackClosure->mOverrunningGlyphs =
|
||||||
PostLayoutCallback(iLineRef, gCallbackClosure->mTextRun,
|
PostLayoutCallback(iLineRef, gCallbackClosure->mTextRun,
|
||||||
gCallbackClosure->mString, gCallbackClosure->mWrapped,
|
gCallbackClosure->mString, gCallbackClosure->mWrapped,
|
||||||
gCallbackClosure->mUnmatchedChars);
|
gCallbackClosure->mUnmatchedChars,
|
||||||
|
gCallbackClosure->mSegmentStart,
|
||||||
|
gCallbackClosure->mSegmentLength);
|
||||||
*oCallbackStatus = kATSULayoutOperationCallbackStatusContinue;
|
*oCallbackStatus = kATSULayoutOperationCallbackStatusContinue;
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
PRBool
|
||||||
gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
const PRUnichar *aString, PRUint32 aLength,
|
const PRUnichar *aString, PRUint32 aLength,
|
||||||
PRBool aWrapped)
|
PRBool aWrapped, PRUint32 aSegmentStart,
|
||||||
|
PRUint32 aSegmentLength)
|
||||||
{
|
{
|
||||||
OSStatus status;
|
OSStatus status;
|
||||||
gfxAtsuiFont *atsuiFont = GetFontAt(0);
|
gfxAtsuiFont *atsuiFont = GetFontAt(0);
|
||||||
|
@ -802,17 +908,16 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
nsTArray<ATSUStyle> stylesToDispose;
|
nsTArray<ATSUStyle> stylesToDispose;
|
||||||
PRUint32 headerChars = aWrapped ? 1 : 0;
|
PRUint32 headerChars = aWrapped ? 1 : 0;
|
||||||
const PRUnichar *realString = aString + headerChars;
|
const PRUnichar *realString = aString + headerChars;
|
||||||
PRUint32 realLength = aRun->GetLength();
|
NS_ASSERTION(aSegmentLength == aLength - (aWrapped ? 3 : 0),
|
||||||
NS_ASSERTION(realLength == aLength - (aWrapped ? 3 : 0),
|
|
||||||
"Length mismatch");
|
"Length mismatch");
|
||||||
|
|
||||||
#ifdef DUMP_TEXT_RUNS
|
#ifdef DUMP_TEXT_RUNS
|
||||||
NS_ConvertUTF16toUTF8 str(realString, realLength);
|
NS_ConvertUTF16toUTF8 str(realString, aSegmentLength);
|
||||||
NS_ConvertUTF16toUTF8 families(mFamilies);
|
NS_ConvertUTF16toUTF8 families(mFamilies);
|
||||||
printf("%p(%s) TEXTRUN \"%s\" ENDTEXTRUN\n", this, families.get(), str.get());
|
printf("%p(%s) TEXTRUN \"%s\" ENDTEXTRUN\n", this, families.get(), str.get());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
UniCharCount runLengths = realLength;
|
UniCharCount runLengths = aSegmentLength;
|
||||||
ATSUTextLayout layout;
|
ATSUTextLayout layout;
|
||||||
// Create the text layout for the whole string, but only produce glyphs
|
// Create the text layout for the whole string, but only produce glyphs
|
||||||
// for the text inside LRO/RLO - PDF, if present. For wrapped strings
|
// for the text inside LRO/RLO - PDF, if present. For wrapped strings
|
||||||
|
@ -821,7 +926,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
status = ATSUCreateTextLayoutWithTextPtr
|
status = ATSUCreateTextLayoutWithTextPtr
|
||||||
(aString,
|
(aString,
|
||||||
headerChars,
|
headerChars,
|
||||||
realLength + (aWrapped ? 1 : 0),
|
aSegmentLength + (aWrapped ? 1 : 0),
|
||||||
aLength,
|
aLength,
|
||||||
1,
|
1,
|
||||||
&runLengths,
|
&runLengths,
|
||||||
|
@ -833,6 +938,8 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
closure.mTextRun = aRun;
|
closure.mTextRun = aRun;
|
||||||
closure.mString = realString;
|
closure.mString = realString;
|
||||||
closure.mWrapped = aWrapped;
|
closure.mWrapped = aWrapped;
|
||||||
|
closure.mSegmentStart = aSegmentStart;
|
||||||
|
closure.mSegmentLength = aSegmentLength;
|
||||||
NS_ASSERTION(!gCallbackClosure, "Reentering InitTextRun? Expect disaster!");
|
NS_ASSERTION(!gCallbackClosure, "Reentering InitTextRun? Expect disaster!");
|
||||||
gCallbackClosure = &closure;
|
gCallbackClosure = &closure;
|
||||||
|
|
||||||
|
@ -868,8 +975,8 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
/* Now go through and update the styles for the text, based on font matching. */
|
/* Now go through and update the styles for the text, based on font matching. */
|
||||||
|
|
||||||
UniCharArrayOffset runStart = headerChars;
|
UniCharArrayOffset runStart = headerChars;
|
||||||
UniCharCount totalLength = runStart + realLength;
|
UniCharCount totalLength = runStart + aSegmentLength;
|
||||||
UniCharCount runLength = realLength;
|
UniCharCount runLength = aSegmentLength;
|
||||||
|
|
||||||
//fprintf (stderr, "==== Starting font maching [string length: %d]\n", totalLength);
|
//fprintf (stderr, "==== Starting font maching [string length: %d]\n", totalLength);
|
||||||
while (runStart < totalLength) {
|
while (runStart < totalLength) {
|
||||||
|
@ -882,7 +989,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
if (status == noErr) {
|
if (status == noErr) {
|
||||||
//fprintf (stderr, "ATSUMatchFontsToText returned noErr\n");
|
//fprintf (stderr, "ATSUMatchFontsToText returned noErr\n");
|
||||||
// everything's good, finish up
|
// everything's good, finish up
|
||||||
aRun->AddGlyphRun(atsuiFont, runStart - headerChars);
|
aRun->AddGlyphRun(atsuiFont, aSegmentStart + runStart - headerChars);
|
||||||
break;
|
break;
|
||||||
} else if (status == kATSUFontsMatched) {
|
} else if (status == kATSUFontsMatched) {
|
||||||
//fprintf (stderr, "ATSUMatchFontsToText returned kATSUFontsMatched: FID %d\n", substituteFontID);
|
//fprintf (stderr, "ATSUMatchFontsToText returned kATSUFontsMatched: FID %d\n", substituteFontID);
|
||||||
|
@ -898,14 +1005,14 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
ATSUSetAttributes (subStyle, 1, fontTags, fontArgSizes, fontArgs);
|
ATSUSetAttributes (subStyle, 1, fontTags, fontArgSizes, fontArgs);
|
||||||
|
|
||||||
if (changedOffset > runStart) {
|
if (changedOffset > runStart) {
|
||||||
aRun->AddGlyphRun(atsuiFont, runStart - headerChars);
|
aRun->AddGlyphRun(atsuiFont, aSegmentStart + runStart - headerChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
ATSUSetRunStyle (layout, subStyle, changedOffset, changedLength);
|
ATSUSetRunStyle (layout, subStyle, changedOffset, changedLength);
|
||||||
|
|
||||||
gfxAtsuiFont *font = FindFontFor(substituteFontID);
|
gfxAtsuiFont *font = FindFontFor(substituteFontID);
|
||||||
if (font) {
|
if (font) {
|
||||||
aRun->AddGlyphRun(font, changedOffset - headerChars);
|
aRun->AddGlyphRun(font, aSegmentStart + changedOffset - headerChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
stylesToDispose.AppendElement(subStyle);
|
stylesToDispose.AppendElement(subStyle);
|
||||||
|
@ -913,7 +1020,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
//fprintf (stderr, "ATSUMatchFontsToText returned kATSUFontsNotMatched\n");
|
//fprintf (stderr, "ATSUMatchFontsToText returned kATSUFontsNotMatched\n");
|
||||||
/* I need to select the last resort font; how the heck do I do that? */
|
/* I need to select the last resort font; how the heck do I do that? */
|
||||||
// Record which font is associated with these glyphs, anyway
|
// Record which font is associated with these glyphs, anyway
|
||||||
aRun->AddGlyphRun(atsuiFont, runStart - headerChars);
|
aRun->AddGlyphRun(atsuiFont, aSegmentStart + runStart - headerChars);
|
||||||
|
|
||||||
if (!closure.mUnmatchedChars) {
|
if (!closure.mUnmatchedChars) {
|
||||||
closure.mUnmatchedChars = new PRPackedBool[aLength];
|
closure.mUnmatchedChars = new PRPackedBool[aLength];
|
||||||
|
@ -937,7 +1044,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
// the result of this call.
|
// the result of this call.
|
||||||
ATSTrapezoid trap;
|
ATSTrapezoid trap;
|
||||||
ItemCount trapCount;
|
ItemCount trapCount;
|
||||||
ATSUGetGlyphBounds(layout, 0, 0, headerChars, realLength,
|
ATSUGetGlyphBounds(layout, 0, 0, headerChars, aSegmentLength,
|
||||||
kATSUseFractionalOrigins, 1, &trap, &trapCount);
|
kATSUseFractionalOrigins, 1, &trap, &trapCount);
|
||||||
|
|
||||||
ATSUDisposeTextLayout(layout);
|
ATSUDisposeTextLayout(layout);
|
||||||
|
@ -948,4 +1055,5 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||||
ATSUDisposeStyle(stylesToDispose[i]);
|
ATSUDisposeStyle(stylesToDispose[i]);
|
||||||
}
|
}
|
||||||
gCallbackClosure = nsnull;
|
gCallbackClosure = nsnull;
|
||||||
|
return !closure.mOverrunningGlyphs;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче