diff --git a/gfx/thebes/public/gfxTextRunWordCache.h b/gfx/thebes/public/gfxTextRunWordCache.h
index 8a712f693e1..bc5dc9226a9 100644
--- a/gfx/thebes/public/gfxTextRunWordCache.h
+++ b/gfx/thebes/public/gfxTextRunWordCache.h
@@ -61,7 +61,9 @@ public:
* character. This is used for the context detection necessary for
* bidi.numeral implementation.
*/
- TEXT_INCOMING_ARABICCHAR = 0x40000000
+ TEXT_INCOMING_ARABICCHAR = 0x40000000,
+
+ TEXT_UNUSED_FLAGS = 0x80000000
};
/**
diff --git a/gfx/thebes/src/gfxFont.cpp b/gfx/thebes/src/gfxFont.cpp
index b5ec902a92d..77ddfad369a 100644
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -1394,6 +1394,10 @@ gfxTextRun::~gfxTextRun()
{
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
AccountStorageForTextRun(this, -1);
+#endif
+#ifdef DEBUG
+ // Make it easy to detect a dead text run
+ mFlags = 0xFFFFFFFF;
#endif
NS_RELEASE(mFontGroup);
MOZ_COUNT_DTOR(gfxTextRun);
diff --git a/layout/generic/crashtests/430332-1.html b/layout/generic/crashtests/430332-1.html
new file mode 100644
index 00000000000..c9ba0022991
--- /dev/null
+++ b/layout/generic/crashtests/430332-1.html
@@ -0,0 +1,17 @@
+
+
+
+ab cd
+ab cd
+ab cd
+ab cd
+ab cd
+ab cd
+ab cd
+ab cdef
+
+
+
diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp
index fb3522ad2a9..afd96401081 100644
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -615,6 +615,12 @@ public:
mCurrentRunContextInfo(nsTextFrameUtils::INCOMING_NONE) {
ResetRunInfo();
}
+ ~BuildTextRunsScanner() {
+ NS_ASSERTION(mBreakSinks.IsEmpty(), "Should have been cleared");
+ NS_ASSERTION(mTextRunsToDelete.IsEmpty(), "Should have been cleared");
+ NS_ASSERTION(mLineBreakBeforeFrames.IsEmpty(), "Should have been cleared");
+ NS_ASSERTION(mMappedFlows.IsEmpty(), "Should have been cleared");
+ }
void SetAtStartOfLine() {
mStartOfLine = PR_TRUE;
@@ -641,6 +647,7 @@ public:
void ScanFrame(nsIFrame* aFrame);
PRBool IsTextRunValidForMappedFlows(gfxTextRun* aTextRun);
void FlushFrames(PRBool aFlushLineBreaks, PRBool aSuppressTrailingBreak);
+ void FlushLineBreaks(gfxTextRun* aTrailingTextRun);
void ResetRunInfo() {
mLastFrame = nsnull;
mMappedFlows.Clear();
@@ -648,10 +655,6 @@ public:
mMaxTextLength = 0;
mDoubleByteText = PR_FALSE;
}
- void ResetLineBreaker() {
- PRBool trailingBreak;
- mLineBreaker.Reset(&trailingBreak);
- }
void AccumulateRunInfo(nsTextFrame* aFrame);
/**
* @return null to indicate either textrun construction failed or
@@ -727,6 +730,18 @@ public:
aCapitalize, mContext);
}
+ void Finish() {
+ NS_ASSERTION(!(mTextRun->GetFlags() &
+ (gfxTextRunWordCache::TEXT_UNUSED_FLAGS |
+ nsTextFrameUtils::TEXT_UNUSED_FLAG)),
+ "Flag set that should never be set! (memory safety error?)");
+ if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED) {
+ nsTransformedTextRun* transformedTextRun =
+ static_cast(mTextRun);
+ transformedTextRun->FinishSettingProperties(mContext);
+ }
+ }
+
gfxTextRun* mTextRun;
gfxContext* mContext;
PRUint32 mOffsetIntoTextRun;
@@ -738,6 +753,7 @@ private:
nsAutoTArray mMappedFlows;
nsAutoTArray mLineBreakBeforeFrames;
nsAutoTArray,10> mBreakSinks;
+ nsAutoTArray mTextRunsToDelete;
nsLineBreaker mLineBreaker;
gfxTextRun* mCurrentFramesAllSameTextRun;
gfxContext* mContext;
@@ -1075,12 +1091,15 @@ BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame,
if (seenStartLine) {
++linesAfterStartLine;
if (linesAfterStartLine >= NUM_LINES_TO_BUILD_TEXT_RUNS && scanner.CanStopOnThisLine()) {
- // Don't flush; we may be in the middle of a textrun that we can't
- // end here. That's OK, we just won't build it.
+ // Don't flush frames; we may be in the middle of a textrun
+ // that we can't end here. That's OK, we just won't build it.
// Note that we must already have finished the textrun for aForFrame,
// because we've seen the end of a textrun in a line after the line
// containing aForFrame.
- scanner.ResetLineBreaker();
+ scanner.FlushLineBreaks(nsnull);
+ // This flushes out mMappedFlows and mLineBreakBeforeFrames, which
+ // silences assertions in the scanner destructor.
+ scanner.ResetRunInfo();
return;
}
}
@@ -1132,56 +1151,72 @@ void BuildTextRunsScanner::FlushFrames(PRBool aFlushLineBreaks, PRBool aSuppress
if (mMappedFlows.Length() == 0)
return;
- gfxTextRun* textRun;
- if (!mSkipIncompleteTextRuns && mCurrentFramesAllSameTextRun &&
- ((mCurrentFramesAllSameTextRun->GetFlags() & nsTextFrameUtils::TEXT_INCOMING_WHITESPACE) != 0) ==
- ((mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) != 0) &&
- ((mCurrentFramesAllSameTextRun->GetFlags() & gfxTextRunWordCache::TEXT_INCOMING_ARABICCHAR) != 0) ==
- ((mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) != 0) &&
- IsTextRunValidForMappedFlows(mCurrentFramesAllSameTextRun)) {
- // Optimization: We do not need to (re)build the textrun.
- textRun = mCurrentFramesAllSameTextRun;
+ gfxTextRun* textRun = nsnull;
+ if (!mMappedFlows.IsEmpty()) {
+ if (!mSkipIncompleteTextRuns && mCurrentFramesAllSameTextRun &&
+ ((mCurrentFramesAllSameTextRun->GetFlags() & nsTextFrameUtils::TEXT_INCOMING_WHITESPACE) != 0) ==
+ ((mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) != 0) &&
+ ((mCurrentFramesAllSameTextRun->GetFlags() & gfxTextRunWordCache::TEXT_INCOMING_ARABICCHAR) != 0) ==
+ ((mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) != 0) &&
+ IsTextRunValidForMappedFlows(mCurrentFramesAllSameTextRun)) {
+ // Optimization: We do not need to (re)build the textrun.
+ textRun = mCurrentFramesAllSameTextRun;
- // Feed this run's text into the linebreaker to provide context. This also
- // updates mNextRunContextInfo appropriately.
- SetupBreakSinksForTextRun(textRun, PR_TRUE, PR_FALSE);
- mNextRunContextInfo = nsTextFrameUtils::INCOMING_NONE;
- if (textRun->GetFlags() & nsTextFrameUtils::TEXT_TRAILING_WHITESPACE) {
- mNextRunContextInfo |= nsTextFrameUtils::INCOMING_WHITESPACE;
+ // Feed this run's text into the linebreaker to provide context. This also
+ // updates mNextRunContextInfo appropriately.
+ SetupBreakSinksForTextRun(textRun, PR_TRUE, PR_FALSE);
+ mNextRunContextInfo = nsTextFrameUtils::INCOMING_NONE;
+ if (textRun->GetFlags() & nsTextFrameUtils::TEXT_TRAILING_WHITESPACE) {
+ mNextRunContextInfo |= nsTextFrameUtils::INCOMING_WHITESPACE;
+ }
+ if (textRun->GetFlags() & gfxTextRunWordCache::TEXT_TRAILING_ARABICCHAR) {
+ mNextRunContextInfo |= nsTextFrameUtils::INCOMING_ARABICCHAR;
+ }
+ } else {
+ nsAutoTArray buffer;
+ if (!buffer.AppendElements(mMaxTextLength*(mDoubleByteText ? 2 : 1)))
+ return;
+ textRun = BuildTextRunForFrames(buffer.Elements());
}
- if (textRun->GetFlags() & gfxTextRunWordCache::TEXT_TRAILING_ARABICCHAR) {
- mNextRunContextInfo |= nsTextFrameUtils::INCOMING_ARABICCHAR;
- }
- } else {
- nsAutoTArray buffer;
- if (!buffer.AppendElements(mMaxTextLength*(mDoubleByteText ? 2 : 1)))
- return;
- textRun = BuildTextRunForFrames(buffer.Elements());
}
if (aFlushLineBreaks) {
- PRBool trailingLineBreak;
- nsresult rv = mLineBreaker.Reset(&trailingLineBreak);
- // textRun may be null for various reasons, including because we constructed
- // a partial textrun just to get the linebreaker and other state set up
- // to build the next textrun.
- if (NS_SUCCEEDED(rv) && trailingLineBreak && textRun && !aSuppressTrailingBreak) {
- textRun->SetFlagBits(nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK);
- }
- PRUint32 i;
- for (i = 0; i < mBreakSinks.Length(); ++i) {
- if (!mBreakSinks[i]->mExistingTextRun || mBreakSinks[i]->mChangedBreaks) {
- // TODO cause frames associated with the textrun to be reflowed, if they
- // aren't being reflowed already!
- }
- }
- mBreakSinks.Clear();
+ FlushLineBreaks(aSuppressTrailingBreak ? nsnull : textRun);
}
mCanStopOnThisLine = PR_TRUE;
ResetRunInfo();
}
+void BuildTextRunsScanner::FlushLineBreaks(gfxTextRun* aTrailingTextRun)
+{
+ PRBool trailingLineBreak;
+ nsresult rv = mLineBreaker.Reset(&trailingLineBreak);
+ // textRun may be null for various reasons, including because we constructed
+ // a partial textrun just to get the linebreaker and other state set up
+ // to build the next textrun.
+ if (NS_SUCCEEDED(rv) && trailingLineBreak && aTrailingTextRun) {
+ aTrailingTextRun->SetFlagBits(nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK);
+ }
+
+ PRUint32 i;
+ for (i = 0; i < mBreakSinks.Length(); ++i) {
+ if (!mBreakSinks[i]->mExistingTextRun || mBreakSinks[i]->mChangedBreaks) {
+ // TODO cause frames associated with the textrun to be reflowed, if they
+ // aren't being reflowed already!
+ }
+ mBreakSinks[i]->Finish();
+ }
+ mBreakSinks.Clear();
+
+ for (i = 0; i < mTextRunsToDelete.Length(); ++i) {
+ gfxTextRun* deleteTextRun = mTextRunsToDelete[i];
+ gTextRuns->RemoveFromCache(deleteTextRun);
+ delete deleteTextRun;
+ }
+ mTextRunsToDelete.Clear();
+}
+
void BuildTextRunsScanner::AccumulateRunInfo(nsTextFrame* aFrame)
{
NS_ASSERTION(mMaxTextLength <= mMaxTextLength + aFrame->GetContentLength(), "integer overflow");
@@ -1493,15 +1528,18 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
TextRunMappedFlow dummyMappedFlow;
TextRunUserData* userData;
+ TextRunUserData* userDataToDestroy;
// If the situation is particularly simple (and common) we don't need to
// allocate userData.
if (mMappedFlows.Length() == 1 && !mMappedFlows[0].mEndFrame &&
mMappedFlows[0].mStartFrame->GetContentOffset() == 0) {
userData = &dummyData;
+ userDataToDestroy = nsnull;
dummyData.mMappedFlows = &dummyMappedFlow;
} else {
userData = static_cast
(nsMemory::Alloc(sizeof(TextRunUserData) + mMappedFlows.Length()*sizeof(TextRunMappedFlow)));
+ userDataToDestroy = userData;
userData->mMappedFlows = reinterpret_cast(userData + 1);
}
userData->mMappedFlowCount = mMappedFlows.Length();
@@ -1578,7 +1616,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
// then expand.
nsAutoTArray tempBuf;
if (!tempBuf.AppendElements(contentLength)) {
- DestroyUserData(userData);
+ DestroyUserData(userDataToDestroy);
return nsnull;
}
PRUint8* bufStart = tempBuf.Elements();
@@ -1606,7 +1644,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
// Check for out-of-memory in gfxSkipCharsBuilder
if (!builder.IsOK()) {
- DestroyUserData(userData);
+ DestroyUserData(userDataToDestroy);
return nsnull;
}
@@ -1641,7 +1679,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
nsTextFrame* firstFrame = mMappedFlows[0].mStartFrame;
gfxFontGroup* fontGroup = GetFontGroupForFrame(firstFrame);
if (!fontGroup) {
- DestroyUserData(userData);
+ DestroyUserData(userDataToDestroy);
return nsnull;
}
@@ -1751,7 +1789,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
}
}
if (!textRun) {
- DestroyUserData(userData);
+ DestroyUserData(userDataToDestroy);
return nsnull;
}
@@ -1764,11 +1802,16 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
if (mSkipIncompleteTextRuns) {
mSkipIncompleteTextRuns = !TextContainsLineBreakerWhiteSpace(textPtr,
transformedLength, mDoubleByteText);
-
- // Nuke the textrun
- gTextRuns->RemoveFromCache(textRun);
- delete textRun;
- DestroyUserData(userData);
+ // Arrange for this textrun to be deleted the next time the linebreaker
+ // is flushed out
+ mTextRunsToDelete.AppendElement(textRun);
+ // Since we're doing to destroy the user data now, avoid a dangling
+ // pointer. Strictly speaking we don't need to do this since it should
+ // not be used (since this textrun will not be used and will be
+ // itself deleted soon), but it's always better to not have dangling
+ // pointers around.
+ textRun->SetUserData(nsnull);
+ DestroyUserData(userDataToDestroy);
return nsnull;
}
diff --git a/layout/generic/nsTextFrameUtils.h b/layout/generic/nsTextFrameUtils.h
index 92b8bb7b5e6..92456815087 100644
--- a/layout/generic/nsTextFrameUtils.h
+++ b/layout/generic/nsTextFrameUtils.h
@@ -66,6 +66,7 @@ public:
// the original text has at least one soft hyphen character
TEXT_HAS_SHY = 0x020000,
TEXT_WAS_TRANSFORMED = 0x040000,
+ TEXT_UNUSED_FLAG = 0x080000,
// The following flags are set by nsTextFrame
diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp
index 34f6fb5b9f0..53023e4cc6e 100644
--- a/layout/generic/nsTextRunTransformations.cpp
+++ b/layout/generic/nsTextRunTransformations.cpp
@@ -72,7 +72,7 @@ nsTransformedTextRun::SetCapitalization(PRUint32 aStart, PRUint32 aLength,
memset(mCapitalize.Elements(), 0, GetLength()*sizeof(PRPackedBool));
}
memcpy(mCapitalize.Elements() + aStart, aCapitalization, aLength*sizeof(PRPackedBool));
- mFactory->RebuildTextRun(this, aRefContext);
+ mNeedsRebuild = PR_TRUE;
}
PRBool
@@ -82,76 +82,20 @@ nsTransformedTextRun::SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
{
PRBool changed = gfxTextRun::SetPotentialLineBreaks(aStart, aLength,
aBreakBefore, aRefContext);
- mFactory->RebuildTextRun(this, aRefContext);
+ if (changed) {
+ mNeedsRebuild = PR_TRUE;
+ }
return changed;
}
-PRBool
-nsTransformedTextRun::SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
- PRBool aLineBreakBefore, PRBool aLineBreakAfter,
- gfxFloat* aAdvanceWidthDelta,
- gfxContext* aRefContext)
-{
- nsTArray newBreaks;
- PRUint32 i;
- PRBool changed = PR_FALSE;
- for (i = 0; i < mLineBreaks.Length(); ++i) {
- PRUint32 pos = mLineBreaks[i];
- if (pos >= aStart)
- break;
- newBreaks.AppendElement(pos);
- }
- if (aLineBreakBefore != (i < mLineBreaks.Length() &&
- mLineBreaks[i] == aStart)) {
- changed = PR_TRUE;
- }
- if (aLineBreakBefore) {
- nsTextFrameUtils::AppendLineBreakOffset(&newBreaks, aStart);
- }
- if (aLineBreakAfter != (i + 1 < mLineBreaks.Length() &&
- mLineBreaks[i + 1] == aStart + aLength)) {
- changed = PR_TRUE;
- }
- if (aLineBreakAfter) {
- nsTextFrameUtils::AppendLineBreakOffset(&newBreaks, aStart + aLength);
- }
- for (; i < mLineBreaks.Length(); ++i) {
- if (mLineBreaks[i] > aStart + aLength)
- break;
- changed = PR_TRUE;
- }
- if (!changed) {
- if (aAdvanceWidthDelta) {
- *aAdvanceWidthDelta = 0;
- }
- return PR_FALSE;
- }
-
- newBreaks.AppendElements(mLineBreaks.Elements() + i, mLineBreaks.Length() - i);
- mLineBreaks.SwapElements(newBreaks);
-
- gfxFloat currentAdvance = GetAdvanceWidth(aStart, aLength, nsnull);
- mFactory->RebuildTextRun(this, aRefContext);
- if (aAdvanceWidthDelta) {
- *aAdvanceWidthDelta = GetAdvanceWidth(aStart, aLength, nsnull) - currentAdvance;
- }
- return PR_TRUE;
-}
-
gfxTextRun*
nsTransformingTextRunFactory::MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
const gfxTextRunFactory::Parameters* aParams,
gfxFontGroup* aFontGroup, PRUint32 aFlags,
nsStyleContext** aStyles, PRBool aOwnsFactory)
{
- nsTransformedTextRun* textRun =
- nsTransformedTextRun::Create(aParams, this, aFontGroup,
- aString, aLength, aFlags, aStyles, aOwnsFactory);
- if (!textRun)
- return nsnull;
-
- RebuildTextRun(textRun, aParams->mContext);
- return textRun;
+ return nsTransformedTextRun::Create(aParams, this, aFontGroup,
+ aString, aLength, aFlags, aStyles, aOwnsFactory);
}
gfxTextRun*
@@ -271,7 +215,7 @@ GetParametersForInner(nsTransformedTextRun* aTextRun, PRUint32* aFlags,
{
gfxTextRunFactory::Parameters params =
{ aRefContext, nsnull, nsnull,
- nsnull, nsnull, aTextRun->GetAppUnitsPerDevUnit()
+ nsnull, 0, aTextRun->GetAppUnitsPerDevUnit()
};
*aFlags = aTextRun->GetFlags() & ~gfxFontGroup::TEXT_IS_PERSISTENT;
return params;
@@ -313,17 +257,9 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
PRBool runIsLowercase = PR_FALSE;
nsAutoTArray styleArray;
nsAutoTArray canBreakBeforeArray;
- nsAutoTArray lineBreakBeforeArray;
- PRUint32 nextLineBreak = 0;
PRUint32 i;
for (i = 0; i <= length; ++i) {
- if (nextLineBreak < aTextRun->mLineBreaks.Length() &&
- aTextRun->mLineBreaks[nextLineBreak] == i) {
- lineBreakBeforeArray.AppendElement(i - runStart);
- ++nextLineBreak;
- }
-
PRBool isLowercase = PR_FALSE;
if (i < length) {
// Characters that aren't the start of a cluster are ignored here. They
@@ -346,9 +282,7 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
nsAutoPtr transformedChild;
gfxTextRunCache::AutoTextRun cachedChild;
gfxTextRun* child;
- // Setup actual line break data for child (which may affect shaping)
- innerParams.mInitialBreaks = lineBreakBeforeArray.Elements();
- innerParams.mInitialBreakCount = lineBreakBeforeArray.Length();
+
if (runIsLowercase) {
transformedChild = uppercaseFactory.MakeTextRun(str + runStart, i - runStart,
&innerParams, smallFont, flags, styleArray.Elements(), PR_FALSE);
@@ -372,10 +306,6 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
runStart = i;
styleArray.Clear();
canBreakBeforeArray.Clear();
- lineBreakBeforeArray.Clear();
- if (nextLineBreak > 0 && aTextRun->mLineBreaks[nextLineBreak - 1] == i) {
- lineBreakBeforeArray.AppendElement(0);
- }
}
if (i < length) {
@@ -384,8 +314,6 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
canBreakBeforeArray.AppendElement(aTextRun->CanBreakLineBefore(i));
}
}
- NS_ASSERTION(nextLineBreak == aTextRun->mLineBreaks.Length(),
- "lost track of line breaks somehow");
}
void
@@ -404,8 +332,6 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
nsAutoTArray charsToMergeArray;
nsAutoTArray styleArray;
nsAutoTArray canBreakBeforeArray;
- nsAutoTArray lineBreakBeforeArray;
- PRUint32 nextLineBreak = 0;
PRUint32 extraCharsCount = 0;
PRUint32 i;
@@ -415,11 +341,6 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
charsToMergeArray.AppendElement(PR_FALSE);
styleArray.AppendElement(styles[i]);
canBreakBeforeArray.AppendElement(aTextRun->CanBreakLineBefore(i));
- if (nextLineBreak < aTextRun->mLineBreaks.Length() &&
- aTextRun->mLineBreaks[nextLineBreak] == i) {
- lineBreakBeforeArray.AppendElement(i + extraCharsCount);
- ++nextLineBreak;
- }
PRUint8 style = mAllUppercase ? NS_STYLE_TEXT_TRANSFORM_UPPERCASE
: styles[i]->GetStyleText()->mTextTransform;
@@ -461,13 +382,6 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
canBreakBeforeArray.AppendElement(PR_FALSE);
}
}
- if (nextLineBreak < aTextRun->mLineBreaks.Length() &&
- aTextRun->mLineBreaks[nextLineBreak] == length) {
- lineBreakBeforeArray.AppendElement(length + extraCharsCount);
- ++nextLineBreak;
- }
- NS_ASSERTION(nextLineBreak == aTextRun->mLineBreaks.Length(),
- "lost track of line breaks somehow");
PRUint32 flags;
gfxTextRunFactory::Parameters innerParams =
@@ -477,9 +391,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
nsAutoPtr transformedChild;
gfxTextRunCache::AutoTextRun cachedChild;
gfxTextRun* child;
- // Setup actual line break data for child (which may affect shaping)
- innerParams.mInitialBreaks = lineBreakBeforeArray.Elements();
- innerParams.mInitialBreakCount = lineBreakBeforeArray.Length();
+
if (mInnerTransformingTextRunFactory) {
transformedChild = mInnerTransformingTextRunFactory->MakeTextRun(
convertedString.BeginReading(), convertedString.Length(),
diff --git a/layout/generic/nsTextRunTransformations.h b/layout/generic/nsTextRunTransformations.h
index 86c09f79608..cd9baa21ab5 100644
--- a/layout/generic/nsTextRunTransformations.h
+++ b/layout/generic/nsTextRunTransformations.h
@@ -113,22 +113,30 @@ public:
}
}
- virtual void SetCapitalization(PRUint32 aStart, PRUint32 aLength,
- PRPackedBool* aCapitalization,
- gfxContext* aRefContext);
+ void SetCapitalization(PRUint32 aStart, PRUint32 aLength,
+ PRPackedBool* aCapitalization,
+ gfxContext* aRefContext);
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aBreakBefore,
gfxContext* aRefContext);
- virtual PRBool SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
- PRBool aLineBreakBefore, PRBool aLineBreakAfter,
- gfxFloat* aAdvanceWidthDelta,
- gfxContext* aRefContext);
+ /**
+ * Called after SetCapitalization and SetPotentialLineBreaks
+ * are done and before we request any data from the textrun. Also always
+ * called after a Create.
+ */
+ void FinishSettingProperties(gfxContext* aRefContext)
+ {
+ if (mNeedsRebuild) {
+ mNeedsRebuild = PR_FALSE;
+ mFactory->RebuildTextRun(this, aRefContext);
+ }
+ }
nsTransformingTextRunFactory *mFactory;
- nsTArray mLineBreaks;
nsTArray > mStyles;
nsTArray mCapitalize;
PRPackedBool mOwnsFactory;
+ PRPackedBool mNeedsRebuild;
private:
nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams,
@@ -138,15 +146,12 @@ private:
const PRUint32 aFlags, nsStyleContext** aStyles,
PRBool aOwnsFactory)
: gfxTextRun(aParams, aString, aLength, aFontGroup, aFlags, sizeof(nsTransformedTextRun)),
- mFactory(aFactory), mOwnsFactory(aOwnsFactory)
+ mFactory(aFactory), mOwnsFactory(aOwnsFactory), mNeedsRebuild(PR_TRUE)
{
PRUint32 i;
for (i = 0; i < aLength; ++i) {
mStyles.AppendElement(aStyles[i]);
}
- for (i = 0; i < aParams->mInitialBreakCount; ++i) {
- mLineBreaks.AppendElement(aParams->mInitialBreaks[i]);
- }
}
};