diff --git a/mozilla/gfx/thebes/public/gfxAtsuiFonts.h b/mozilla/gfx/thebes/public/gfxAtsuiFonts.h index 9bdb133fb17..43c2f1413e1 100644 --- a/mozilla/gfx/thebes/public/gfxAtsuiFonts.h +++ b/mozilla/gfx/thebes/public/gfxAtsuiFonts.h @@ -160,9 +160,27 @@ protected: PRUint32 GuessMaximumStringLength(); - /** Returns true for success */ - PRBool InitTextRun(gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength, - PRBool aWrapped, PRUint32 aSegmentStart, PRUint32 aSegmentLength); + /** + * @param aRun the text run to fill in + * @param aString the complete text including all wrapper characters + * @param aLength the length of aString + * @param aLayoutStart the first character of aString that should be + * at the start of the ATSUI layout; this skips any wrapper character + * used to override direction + * @param aLayoutLength the length of the characters that should be + * in the ATSUI layout; this excludes any trailing wrapper character + * used to override direction + * @param aTrailingCharsToIgnore the number of trailing characters + * in the ATSUI layout that are not part of the text run + * (characters added to ensure correct RTL and kerning behaviour) + * @param aTextRunOffset the character offset in the textrun where + * the glyph data from the ATSUI layout should be copied + * @return true for success + */ + PRBool InitTextRun(gfxTextRun *aRun, + const PRUnichar *aString, PRUint32 aLength, + PRUint32 aLayoutStart, PRUint32 aLayoutLength, + PRUint32 aOffsetInTextRun, PRUint32 aLengthInTextRun); // cache the most recent pref font to avoid general pref font lookup nsRefPtr mLastPrefFamily; diff --git a/mozilla/gfx/thebes/src/gfxAtsuiFonts.cpp b/mozilla/gfx/thebes/src/gfxAtsuiFonts.cpp index eba26f5082a..8c359b884b5 100644 --- a/mozilla/gfx/thebes/src/gfxAtsuiFonts.cpp +++ b/mozilla/gfx/thebes/src/gfxAtsuiFonts.cpp @@ -549,12 +549,35 @@ SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString) #define UNICODE_PDF 0x202c static void -AppendDirectionalIndicator(PRUint32 aFlags, nsAString& aString) +AppendDirectionalIndicatorStart(PRUint32 aFlags, nsAString& aString) { static const PRUnichar overrides[2] = { UNICODE_LRO, UNICODE_RLO }; aString.Append(overrides[(aFlags & gfxTextRunFactory::TEXT_IS_RTL) != 0]); } +// Returns the number of trailing characters that should be part of the +// layout but should be ignored +static PRUint32 +AppendDirectionalIndicatorEnd(PRBool aNeedDirection, nsAString& aString) +{ + // Ensure that we compute the full advance width for the last character + // in the string --- we don't want that character to form a kerning + // pair (or a ligature) with the '.' we may append next, + // so we append a space now. + // Even if the character is the last character in the layout, + // we want its width to be determined as if it had a space after it, + // for consistency with the bidi path and during textrun caching etc. + aString.Append(' '); + if (!aNeedDirection) + return 1; + + // Ensure that none of the whitespace in the run is considered "trailing" + // by ATSUI's bidi algorithm + aString.Append('.'); + aString.Append(UNICODE_PDF); + return 2; +} + /** * 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 @@ -646,13 +669,16 @@ gfxAtsuiFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength, PRUint32 len = FindTextRunSegmentLength(textRun, start, maxLen); utf16.Truncate(); - AppendDirectionalIndicator(aFlags, utf16); + AppendDirectionalIndicatorStart(aFlags, utf16); + PRUint32 layoutStart = utf16.Length(); utf16.Append(aString + start, len); // Ensure that none of the whitespace in the run is considered "trailing" // by ATSUI's bidi algorithm - utf16.Append('.'); - utf16.Append(UNICODE_PDF); - if (!InitTextRun(textRun, utf16.get(), utf16.Length(), PR_TRUE, + PRUint32 trailingCharsToIgnore = + AppendDirectionalIndicatorEnd(PR_TRUE, utf16); + PRUint32 layoutLength = len + trailingCharsToIgnore; + if (!InitTextRun(textRun, utf16.get(), utf16.Length(), + layoutStart, layoutLength, start, len) && maxLen > 1) break; start += len; @@ -688,14 +714,15 @@ gfxAtsuiFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength, utf16.Truncate(); PRBool wrapBidi = (aFlags & TEXT_IS_RTL) != 0; if (wrapBidi) { - AppendDirectionalIndicator(aFlags, utf16); + AppendDirectionalIndicatorStart(aFlags, utf16); } + PRUint32 layoutStart = utf16.Length(); AppendASCIItoUTF16(cString, utf16); - if (wrapBidi) { - utf16.Append('.'); - utf16.Append(UNICODE_PDF); - } - if (!InitTextRun(textRun, utf16.get(), utf16.Length(), wrapBidi, + PRUint32 trailingCharsToIgnore = + AppendDirectionalIndicatorEnd(wrapBidi, utf16); + PRUint32 layoutLength = len + trailingCharsToIgnore; + if (!InitTextRun(textRun, utf16.get(), utf16.Length(), + layoutStart, layoutLength, start, len) && maxLen > 1) break; start += len; @@ -922,7 +949,7 @@ GetAdvanceAppUnits(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount, static void SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount, Fixed *aBaselineDeltas, PRUint32 aAppUnitsPerDevUnit, - gfxTextRun *aRun, PRUint32 aSegmentStart, + gfxTextRun *aRun, PRUint32 aOffsetInTextRun, const PRPackedBool *aUnmatched, const PRUnichar *aString, const PRUint32 aLength) @@ -962,11 +989,11 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount, if (NS_IS_HIGH_SURROGATE(aString[index]) && index + 1 < aLength && NS_IS_LOW_SURROGATE(aString[index + 1])) { - aRun->SetMissingGlyph(aSegmentStart + index, + aRun->SetMissingGlyph(aOffsetInTextRun + index, SURROGATE_TO_UCS4(aString[index], aString[index + 1])); } else { - aRun->SetMissingGlyph(aSegmentStart + index, aString[index]); + aRun->SetMissingGlyph(aOffsetInTextRun + index, aString[index]); } } return; @@ -979,7 +1006,7 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount, // Also make them not be cluster boundaries, i.e., fuse them into a cluster, // if the glyphs are out of character order. for (offset = firstOffset + 2; offset <= lastOffset; offset += 2) { - PRUint32 charIndex = aSegmentStart + offset/2; + PRUint32 charIndex = aOffsetInTextRun + offset/2; PRBool makeClusterStart = inOrder && aRun->IsClusterStart(charIndex); g.SetComplex(makeClusterStart, PR_FALSE, 0); aRun->SetGlyphs(charIndex, g, nsnull); @@ -987,7 +1014,7 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount, // Grab total advance for all glyphs PRInt32 advance = GetAdvanceAppUnits(aGlyphs, aGlyphCount, aAppUnitsPerDevUnit); - PRUint32 charIndex = aSegmentStart + firstOffset/2; + PRUint32 charIndex = aOffsetInTextRun + firstOffset/2; if (regularGlyphCount == 1) { if (advance >= 0 && (!aBaselineDeltas || aBaselineDeltas[displayGlyph - aGlyphs] == 0) && @@ -1005,7 +1032,7 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount, ATSLayoutRecord *glyph = &aGlyphs[i]; if (glyph->glyphID != ATSUI_SPECIAL_GLYPH_ID) { if (glyph->originalOffset > firstOffset) { - PRUint32 glyphCharIndex = aSegmentStart + glyph->originalOffset/2; + PRUint32 glyphCharIndex = aOffsetInTextRun + glyph->originalOffset/2; PRUint32 glyphRunIndex = aRun->FindFirstGlyphRunContaining(glyphCharIndex); PRUint32 numGlyphRuns; const gfxTextRun::GlyphRun *glyphRun = aRun->GetGlyphRuns(&numGlyphRuns) + glyphRunIndex; @@ -1048,7 +1075,7 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount, } if (detailedGlyphs.Length() == 0) { NS_WARNING("No glyphs visible at all!"); - aRun->SetGlyphs(aSegmentStart + charIndex, g.SetMissing(0), nsnull); + aRun->SetGlyphs(aOffsetInTextRun + charIndex, g.SetMissing(0), nsnull); return; } @@ -1067,9 +1094,9 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount, */ static PRBool PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun, - const PRUnichar *aString, PRBool aWrapped, - const PRPackedBool *aUnmatched, - PRUint32 aSegmentStart, PRUint32 aSegmentLength) + const PRUnichar *aString, PRUint32 aLayoutLength, + PRUint32 aOffsetInTextRun, PRUint32 aLengthInTextRun, + const PRPackedBool *aUnmatched) { // AutoLayoutDataArrayPtr advanceDeltasArray(aLine, kATSUDirectDataAdvanceDeltaFixedArray); // Fixed *advanceDeltas = static_cast(advanceDeltasArray.mArray); @@ -1095,18 +1122,19 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun, PRUint32 appUnitsPerDevUnit = aRun->GetAppUnitsPerDevUnit(); PRBool isRTL = aRun->IsRightToLeft(); - if (aWrapped) { + PRUint32 trailingCharactersToIgnore = aLayoutLength - aLengthInTextRun; + if (trailingCharactersToIgnore > 0) { // The glyph array includes a glyph for the artificial trailing // non-whitespace character. Strip that glyph from the array now. if (isRTL) { - NS_ASSERTION(glyphRecords[0].originalOffset == aSegmentLength*2, + NS_ASSERTION(glyphRecords[trailingCharactersToIgnore - 1].originalOffset == aLengthInTextRun*2, "Couldn't find glyph for trailing marker"); - glyphRecords++; + glyphRecords += trailingCharactersToIgnore; } else { - NS_ASSERTION(glyphRecords[numGlyphs - 1].originalOffset == aSegmentLength*2, + NS_ASSERTION(glyphRecords[numGlyphs - trailingCharactersToIgnore].originalOffset == aLengthInTextRun*2, "Couldn't find glyph for trailing marker"); } - --numGlyphs; + numGlyphs -= trailingCharactersToIgnore; if (numGlyphs == 0) return PR_FALSE; } @@ -1153,13 +1181,13 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun, SetGlyphsForCharacterGroup(glyphRecords + numGlyphs - glyphCount, glyphCount, baselineDeltas ? baselineDeltas + numGlyphs - glyphCount : nsnull, - appUnitsPerDevUnit, aRun, aSegmentStart, - aUnmatched, aString, aSegmentLength); + appUnitsPerDevUnit, aRun, aOffsetInTextRun, + aUnmatched, aString, aLengthInTextRun); } else { SetGlyphsForCharacterGroup(glyphRecords, glyphCount, baselineDeltas, - appUnitsPerDevUnit, aRun, aSegmentStart, - aUnmatched, aString, aSegmentLength); + appUnitsPerDevUnit, aRun, aOffsetInTextRun, + aUnmatched, aString, aLengthInTextRun); glyphRecords += glyphCount; if (baselineDeltas) { baselineDeltas += glyphCount; @@ -1174,14 +1202,12 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun, struct PostLayoutCallbackClosure { gfxTextRun *mTextRun; const PRUnichar *mString; + PRUint32 mLayoutLength; + PRUint32 mOffsetInTextRun; + PRUint32 mLengthInTextRun; // Either null or an array of stringlength booleans set to true for // each character that did not match any fonts nsAutoArrayPtr 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; }; @@ -1198,10 +1224,11 @@ PostLayoutOperationCallback(ATSULayoutOperationSelector iCurrentOperation, { gCallbackClosure->mOverrunningGlyphs = PostLayoutCallback(iLineRef, gCallbackClosure->mTextRun, - gCallbackClosure->mString, gCallbackClosure->mWrapped, - gCallbackClosure->mUnmatchedChars, - gCallbackClosure->mSegmentStart, - gCallbackClosure->mSegmentLength); + gCallbackClosure->mString, + gCallbackClosure->mLayoutLength, + gCallbackClosure->mOffsetInTextRun, + gCallbackClosure->mLengthInTextRun, + gCallbackClosure->mUnmatchedChars); *oCallbackStatus = kATSULayoutOperationCallbackStatusContinue; return noErr; } @@ -1407,23 +1434,24 @@ SetLayoutRangeToFont(ATSUTextLayout layout, ATSUStyle mainStyle, UniCharArrayOff PRBool gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength, - PRBool aWrapped, PRUint32 aSegmentStart, - PRUint32 aSegmentLength) + PRUint32 aLayoutStart, PRUint32 aLayoutLength, + PRUint32 aOffsetInTextRun, PRUint32 aLengthInTextRun) { OSStatus status; gfxAtsuiFont *firstFont = GetFontAt(0); ATSUStyle mainStyle = firstFont->GetATSUStyle(); nsTArray stylesToDispose; - PRUint32 headerChars = aWrapped ? 1 : 0; - const PRUnichar *realString = aString + headerChars; - NS_ASSERTION(aSegmentLength == aLength - (aWrapped ? 3 : 0), - "Length mismatch"); + const PRUnichar *layoutString = aString + aLayoutStart; #ifdef DUMP_TEXT_RUNS - NS_ConvertUTF16toUTF8 str(realString, aSegmentLength); + NS_ConvertUTF16toUTF8 str(layoutString, aLengthInTextRun); NS_ConvertUTF16toUTF8 families(mFamilies); - PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG, ("InitTextRun %p fontgroup %p (%s) lang: %s len %d TEXTRUN \"%s\" ENDTEXTRUN\n", aRun, this, families.get(), mStyle.langGroup.get(), aSegmentLength, str.get()) ); - PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG, ("InitTextRun font: %s\n", NS_ConvertUTF16toUTF8(firstFont->GetUniqueName()).get()) ); + PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG,\ + ("InitTextRun %p fontgroup %p (%s) lang: %s len %d TEXTRUN \"%s\" ENDTEXTRUN\n", + aRun, this, families.get(), mStyle.langGroup.get(), aLengthInTextRun, str.get()) ); + PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG, + ("InitTextRun font: %s\n", + NS_ConvertUTF16toUTF8(firstFont->GetUniqueName()).get()) ); #endif if (aRun->GetFlags() & TEXT_DISABLE_OPTIONAL_LIGATURES) { @@ -1434,7 +1462,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, } } - UniCharCount runLengths = aSegmentLength; + UniCharCount runLengths = aLengthInTextRun; ATSUTextLayout layout; // Create the text layout for the whole string, but only produce glyphs // for the text inside LRO/RLO - PDF, if present. For wrapped strings @@ -1442,8 +1470,8 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, // character to ensure that ATSUI treats all whitespace as non-trailing. status = ATSUCreateTextLayoutWithTextPtr (aString, - headerChars, - aSegmentLength + (aWrapped ? 1 : 0), + aLayoutStart, + aLayoutLength, aLength, 1, &runLengths, @@ -1453,10 +1481,10 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, PostLayoutCallbackClosure closure; closure.mTextRun = aRun; - closure.mString = realString; - closure.mWrapped = aWrapped; - closure.mSegmentStart = aSegmentStart; - closure.mSegmentLength = aSegmentLength; + closure.mString = layoutString; + closure.mLayoutLength = aLayoutLength; + closure.mOffsetInTextRun = aOffsetInTextRun; + closure.mLengthInTextRun = aLengthInTextRun; NS_ASSERTION(!gCallbackClosure, "Reentering InitTextRun? Expect disaster!"); gCallbackClosure = &closure; @@ -1490,9 +1518,9 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, nsAutoArrayPtr mirroredStr; - UniCharArrayOffset runStart = headerChars; - UniCharCount runLength = aSegmentLength; - UniCharCount totalLength = headerChars + aSegmentLength; + UniCharArrayOffset runStart = aLayoutStart; + UniCharCount runLength = aLengthInTextRun; + UniCharCount totalLength = aLayoutStart + aLengthInTextRun; /// ---- match fonts using cmap info instead of ATSUI ---- @@ -1519,7 +1547,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, // if no matched font, mark as unmatched if (!matchedFont) { - aRun->AddGlyphRun(firstFont, aSegmentStart + runStart - headerChars, PR_TRUE); + aRun->AddGlyphRun(firstFont, aOffsetInTextRun + runStart - aLayoutStart, PR_TRUE); if (!closure.mUnmatchedChars) { closure.mUnmatchedChars = new PRPackedBool[aLength]; @@ -1531,7 +1559,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, if (closure.mUnmatchedChars) { //printf("setting %d unmatched from %d\n", matchedLength, runStart - headerChars); - memset(closure.mUnmatchedChars.get() + runStart - headerChars, + memset(closure.mUnmatchedChars.get() + runStart - aLayoutStart, PR_TRUE, matchedLength); } @@ -1544,7 +1572,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, } // add a glyph run for the matched substring - aRun->AddGlyphRun(matchedFont, aSegmentStart + runStart - headerChars, PR_TRUE); + aRun->AddGlyphRun(matchedFont, aOffsetInTextRun + runStart - aLayoutStart, PR_TRUE); } runStart += matchedLength; @@ -1562,12 +1590,12 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, // the result of this call. ATSTrapezoid trap; ItemCount trapCount; - ATSUGetGlyphBounds(layout, 0, 0, headerChars, aSegmentLength, + ATSUGetGlyphBounds(layout, 0, 0, aLayoutStart, aLengthInTextRun, kATSUseFractionalOrigins, 1, &trap, &trapCount); ATSUDisposeTextLayout(layout); - aRun->AdjustAdvancesForSyntheticBold(aSegmentStart, aSegmentLength); + aRun->AdjustAdvancesForSyntheticBold(aOffsetInTextRun, aLengthInTextRun); PRUint32 i; for (i = 0; i < stylesToDispose.Length(); ++i) { diff --git a/mozilla/layout/reftests/bugs/427730-1-ref.html b/mozilla/layout/reftests/bugs/427730-1-ref.html new file mode 100644 index 00000000000..49c8b3d5ae0 --- /dev/null +++ b/mozilla/layout/reftests/bugs/427730-1-ref.html @@ -0,0 +1,5 @@ + + +

T + + diff --git a/mozilla/layout/reftests/bugs/427730-1.html b/mozilla/layout/reftests/bugs/427730-1.html new file mode 100644 index 00000000000..0cc96f32528 --- /dev/null +++ b/mozilla/layout/reftests/bugs/427730-1.html @@ -0,0 +1,5 @@ + + +

T + + diff --git a/mozilla/layout/reftests/bugs/reftest.list b/mozilla/layout/reftests/bugs/reftest.list index a0da9d5a2c0..87cce637e93 100644 --- a/mozilla/layout/reftests/bugs/reftest.list +++ b/mozilla/layout/reftests/bugs/reftest.list @@ -804,3 +804,5 @@ fails-if(MOZ_WIDGET_TOOLKIT=="gtk2") == 424074-1-ref2.xul 424074-1-ref3.xul == 427129-image.html 427129-ref.html == 427129-table-caption.html 427129-table-caption-ref.html == 427370-1.html 427370-1-ref.html +== 427730-1.html 427730-1-ref.html +