diff --git a/layout/svg/crashtests/898951-1.svg b/layout/svg/crashtests/898951-1.svg
new file mode 100644
index 00000000000..f42dbf69f27
--- /dev/null
+++ b/layout/svg/crashtests/898951-1.svg
@@ -0,0 +1,3 @@
+
diff --git a/layout/svg/crashtests/crashtests.list b/layout/svg/crashtests/crashtests.list
index 79547de2018..753d3f1f438 100644
--- a/layout/svg/crashtests/crashtests.list
+++ b/layout/svg/crashtests/crashtests.list
@@ -174,3 +174,4 @@ load 890783-1.svg
load 893510-1.svg
load 895311-1.svg
load 897342-1.svg
+load 898951-1.svg
diff --git a/layout/svg/nsSVGTextFrame2.cpp b/layout/svg/nsSVGTextFrame2.cpp
index 6846b9bcae9..eaff904adc2 100644
--- a/layout/svg/nsSVGTextFrame2.cpp
+++ b/layout/svg/nsSVGTextFrame2.cpp
@@ -2209,6 +2209,15 @@ public:
return mGlyphStartTextElementCharIndex;
}
+ /**
+ * Returns the number of undisplayed characters between the beginning of
+ * the glyph and the current character.
+ */
+ uint32_t GlyphUndisplayedCharacters() const
+ {
+ return mGlyphUndisplayedCharacters;
+ }
+
/**
* Gets the original character offsets within the nsTextNode for the
* cluster/ligature group the current character is a part of.
@@ -2239,15 +2248,26 @@ public:
/**
* Gets the specified partial advance of the glyph the current character is
- * part of.
+ * part of. The partial advance is measured from the first character
+ * corresponding to the glyph until the specified part length.
+ *
+ * The part length value does not include any undisplayed characters in the
+ * middle of the cluster/ligature group. For example, if you have:
+ *
+ * fxi
+ *
+ * and the "f" and "i" are ligaturized, then calling GetGlyphPartialAdvance
+ * with aPartLength values will have the following results:
+ *
+ * 0 => 0
+ * 1 => adv("fi") / 2
+ * 2 => adv("fi")
*
- * @param aPartOffset The index of the first character, starting from 0, of
- * the cluster/ligature group to measure.
* @param aPartLength The number of characters in the cluster/ligature group
* to measure.
* @param aContext The context to use for unit conversions.
*/
- gfxFloat GetGlyphPartialAdvance(uint32_t aPartOffset, uint32_t aPartLength,
+ gfxFloat GetGlyphPartialAdvance(uint32_t aPartLength,
nsPresContext* aContext) const;
/**
@@ -2278,6 +2298,7 @@ private:
void UpdateGlyphStartTextElementCharIndex() {
if (!IsOriginalCharSkipped() && IsClusterAndLigatureGroupStart()) {
mGlyphStartTextElementCharIndex = mTextElementCharIndex;
+ mGlyphUndisplayedCharacters = 0;
}
}
@@ -2318,6 +2339,14 @@ private:
*/
uint32_t mGlyphStartTextElementCharIndex;
+ /**
+ * If we are iterating in mode eClusterOrLigatureGroupMiddle, then
+ * this tracks how many undisplayed characters were encountered
+ * between the start of this glyph (at mGlyphStartTextElementCharIndex)
+ * and the current character (at mTextElementCharIndex).
+ */
+ uint32_t mGlyphUndisplayedCharacters;
+
/**
* The scale factor to apply to glyph advances returned by
* GetGlyphAdvance etc. to take into account textLength="".
@@ -2479,7 +2508,9 @@ CharIterator::GetOriginalGlyphOffsets(uint32_t& aOriginalOffset,
{
gfxSkipCharsIterator it = TextFrame()->EnsureTextRun(nsTextFrame::eInflated);
it.SetOriginalOffset(mSkipCharsIterator.GetOriginalOffset() -
- (mTextElementCharIndex - mGlyphStartTextElementCharIndex));
+ (mTextElementCharIndex -
+ mGlyphStartTextElementCharIndex -
+ mGlyphUndisplayedCharacters));
while (it.GetSkippedOffset() > 0 &&
(!mTextRun->IsClusterStart(it.GetSkippedOffset()) ||
@@ -2530,15 +2561,13 @@ CharIterator::GetAdvance(nsPresContext* aContext) const
}
gfxFloat
-CharIterator::GetGlyphPartialAdvance(uint32_t aPartOffset, uint32_t aPartLength,
+CharIterator::GetGlyphPartialAdvance(uint32_t aPartLength,
nsPresContext* aContext) const
{
uint32_t offset, length;
GetOriginalGlyphOffsets(offset, length);
- NS_ASSERTION(aPartOffset <= length && aPartOffset + aPartLength <= length,
- "invalid aPartOffset / aPartLength values");
- offset += aPartOffset;
+ NS_ASSERTION(aPartLength <= length, "invalid aPartLength value");
length = aPartLength;
gfxSkipCharsIterator it = TextFrame()->EnsureTextRun(nsTextFrame::eInflated);
@@ -2573,7 +2602,9 @@ CharIterator::NextCharacter()
mFrameIterator.Next();
// Skip any undisplayed characters.
- mTextElementCharIndex += mFrameIterator.UndisplayedCharacters();
+ uint32_t undisplayed = mFrameIterator.UndisplayedCharacters();
+ mGlyphUndisplayedCharacters += undisplayed;
+ mTextElementCharIndex += undisplayed;
if (!TextFrame()) {
// We're at the end.
mSkipCharsIterator = gfxSkipCharsIterator();
@@ -4518,9 +4549,10 @@ nsSVGTextFrame2::AdjustPositionsForClusters()
// Find out the partial glyph advance for this character and update
// the character position.
+ uint32_t partLength =
+ charIndex - startIndex - it.GlyphUndisplayedCharacters();
gfxFloat advance =
- it.GetGlyphPartialAdvance(0, charIndex - startIndex, presContext) /
- mFontSizeScaleFactor;
+ it.GetGlyphPartialAdvance(partLength, presContext) / mFontSizeScaleFactor;
gfxPoint direction = gfxPoint(cos(angle), sin(angle)) *
(it.TextRun()->IsRightToLeft() ? -1.0 : 1.0);
mPositions[charIndex].mPosition = mPositions[startIndex].mPosition +
@@ -4673,7 +4705,7 @@ nsSVGTextFrame2::DoTextPathLayout()
j < mPositions.Length() && mPositions[j].mClusterOrLigatureGroupMiddle;
j++) {
gfxPoint partialAdvance =
- direction * it.GetGlyphPartialAdvance(0, j - i, context) /
+ direction * it.GetGlyphPartialAdvance(j - i, context) /
mFontSizeScaleFactor;
mPositions[j].mPosition = mPositions[i].mPosition + partialAdvance;
mPositions[j].mAngle = mPositions[i].mAngle;