From 7843cf8b89534880128e3edc2bbfdb9c5d8dbd87 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 26 Nov 2008 11:44:05 +1300 Subject: [PATCH] Bug 430332. Lazily rebuild transformed-textruns, deferring rebuild until after the linebreaker has finished analysis. r=smontagu --- layout/generic/nsTextFrameThebes.cpp | 9 ++ layout/generic/nsTextRunTransformations.cpp | 106 ++------------------ layout/generic/nsTextRunTransformations.h | 29 +++--- 3 files changed, 35 insertions(+), 109 deletions(-) diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 70376693067b..479569410ac2 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -714,6 +714,14 @@ public: aCapitalize, mContext); } + void Finish() { + if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED) { + nsTransformedTextRun* transformedTextRun = + static_cast(mTextRun); + transformedTextRun->FinishSettingProperties(mContext); + } + } + gfxTextRun* mTextRun; gfxContext* mContext; PRUint32 mOffsetIntoTextRun; @@ -1129,6 +1137,7 @@ void BuildTextRunsScanner::FlushFrames(PRBool aFlushLineBreaks, PRBool aSuppress // TODO cause frames associated with the textrun to be reflowed, if they // aren't being reflowed already! } + mBreakSinks[i]->Finish(); } mBreakSinks.Clear(); } diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index 34f6fb5b9f0d..53023e4cc6e1 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 86c09f796089..cd9baa21ab52 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]); - } } };