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:
roc+@cs.cmu.edu 2007-05-14 19:54:19 -07:00
Родитель 1229e4399d
Коммит 45323b4ff4
2 изменённых файлов: 186 добавлений и 75 удалений

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

@ -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;
} }