From 942d47af85500dc0abac4808d13123eeea22f87e Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Wed, 9 May 2007 22:04:56 +0000 Subject: [PATCH] Not part of the build. Update new text frame for textrun API changes. Also implements a textrun cache for the new text frame --- layout/generic/nsTextFrameThebes.cpp | 484 +++++++++++--------- layout/generic/nsTextFrameUtils.cpp | 13 +- layout/generic/nsTextFrameUtils.h | 13 +- layout/generic/nsTextRunTransformations.cpp | 77 ++-- layout/generic/nsTextRunTransformations.h | 21 +- 5 files changed, 319 insertions(+), 289 deletions(-) diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index e8a845658f9..9448861a757 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -82,6 +82,8 @@ #include "nsTextFrameUtils.h" #include "nsTextRunTransformations.h" #include "nsFrameManager.h" +#include "nsTextFrameTextRunCache.h" +#include "nsExpirationTracker.h" #include "nsTextFragment.h" #include "nsGkAtoms.h" @@ -556,6 +558,157 @@ protected: void SetOffsets(PRInt32 start, PRInt32 end); }; +static void +DestroyUserData(void* aUserData) +{ + TextRunUserData* userData = NS_STATIC_CAST(TextRunUserData*, aUserData); + if (userData) { + nsMemory::Free(userData); + } +} + +static void +ClearAllTextRunReferences(nsTextFrame* aFrame, gfxTextRun* aTextRun) +{ + aFrame->RemoveStateBits(TEXT_IS_RUN_OWNER); + while (aFrame) { + if (aFrame->GetTextRun() != aTextRun) + break; + aFrame->SetTextRun(nsnull); + aFrame = NS_STATIC_CAST(nsTextFrame*, aFrame->GetNextContinuation()); + } +} + +static void +UnhookTextRunFromFrames(gfxTextRun* aTextRun) +{ + if (!aTextRun->GetUserData()) + return; + + // Kill all references to the textrun. It could be referenced by any of its + // owners, and all their in-flows. + if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { + nsIFrame* firstInFlow = NS_STATIC_CAST(nsIFrame*, aTextRun->GetUserData()); + ClearAllTextRunReferences(NS_STATIC_CAST(nsTextFrame*, firstInFlow), aTextRun); + } else { + TextRunUserData* userData = + NS_STATIC_CAST(TextRunUserData*, aTextRun->GetUserData()); + PRInt32 i; + for (i = 0; i < userData->mMappedFlowCount; ++i) { + ClearAllTextRunReferences(userData->mMappedFlows[i].mStartFrame, aTextRun); + } + DestroyUserData(userData); + } + aTextRun->SetUserData(nsnull); +} + +class FrameTextRunCache; + +static FrameTextRunCache *gTextRuns = nsnull; + +/* + * Cache textruns and expire them after 3*10 seconds of no use. + * Our textruns are either: + * -- not tracked and not in the cache + * -- tracked but not in the cache and nsTextFrameUtils::TEXT_IS_UNCACHED is set + * -- tracked, in the cache, and nsTextFrameUtils::TEXT_IS_UNCACHED is not set + */ +class FrameTextRunCache : public nsExpirationTracker { +public: + enum { TIMEOUT_SECONDS = 10 }; + FrameTextRunCache() + : nsExpirationTracker(TIMEOUT_SECONDS*1000) {} + ~FrameTextRunCache() { + AgeAllGenerations(); + } + + void RemoveFromCache(gfxTextRun* aTextRun) { + RemoveObject(aTextRun); + if (!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_UNCACHED)) { + mCache.RemoveTextRun(aTextRun); + } + } + + // This gets called when the timeout has expired on a gfxTextRun + virtual void NotifyExpired(gfxTextRun* aTextRun) { + UnhookTextRunFromFrames(aTextRun); + RemoveFromCache(aTextRun); + delete aTextRun; + } + + class InnerCache : public gfxTextRunCache { + public: + // If a textrun is removed from the cache, and has no associated frame(s), + // then we may as well destroy it now. We should stop tracking it + // in any case; even if it has an associated frame, there is no point + // in keeping it around after it's dropped from that frame. + virtual void NotifyRemovedFromCache(gfxTextRun* aTextRun) { + if (aTextRun->GetExpirationState()->IsTracked()) { + gTextRuns->RemoveObject(aTextRun); + } + if (aTextRun->GetUserData()) + return; + delete aTextRun; + } + }; + + InnerCache mCache; +}; + +static gfxTextRun * +MakeTextRun(const PRUnichar *aText, PRUint32 aLength, + gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams, + PRUint32 aFlags) +{ + nsAutoPtr textRun; + if (aLength == 0) { + textRun = aFontGroup->MakeEmptyTextRun(aParams, aFlags | nsTextFrameUtils::TEXT_IS_UNCACHED); + } else if (aLength == 1 && aText[0] == ' ') { + textRun = aFontGroup->MakeSpaceTextRun(aParams, aFlags | nsTextFrameUtils::TEXT_IS_UNCACHED); + } else { + textRun = gTextRuns->mCache.GetOrMakeTextRun(aText, aLength, aFontGroup, aParams, aFlags); + } + if (!textRun) + return nsnull; + nsresult rv = gTextRuns->AddObject(textRun); + if (NS_FAILED(rv)) + return nsnull; + return textRun.forget(); +} + +static gfxTextRun * +MakeTextRun(const PRUint8 *aText, PRUint32 aLength, + gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams, + PRUint32 aFlags) +{ + nsAutoPtr textRun; + if (aLength == 0) { + textRun = aFontGroup->MakeEmptyTextRun(aParams, aFlags | nsTextFrameUtils::TEXT_IS_UNCACHED); + } else if (aLength == 1 && aText[0] == ' ') { + textRun = aFontGroup->MakeSpaceTextRun(aParams, aFlags | nsTextFrameUtils::TEXT_IS_UNCACHED); + } else { + textRun = gTextRuns->mCache.GetOrMakeTextRun(aText, aLength, aFontGroup, aParams, aFlags); + } + if (!textRun) + return nsnull; + nsresult rv = gTextRuns->AddObject(textRun); + if (NS_FAILED(rv)) + return nsnull; + return textRun.forget(); +} + +nsresult +nsTextFrameTextRunCache::Init() { + gTextRuns = new FrameTextRunCache(); + return gTextRuns ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +void +nsTextFrameTextRunCache::Shutdown() { + delete gTextRuns; + gTextRuns = nsnull; +} + PRInt32 nsTextFrame::GetInFlowContentLength() { #ifdef IBMBIDI nsTextFrame* nextBidi = nsnull; @@ -692,8 +845,7 @@ public: void BuildTextRunForFrames(void* aTextBuffer); void AssignTextRun(gfxTextRun* aTextRun); nsTextFrame* GetNextBreakBeforeFrame(PRUint32* aIndex); - void SetupBreakSinksForTextRun(gfxTextRun* aTextRun, const void* aText, PRUint32 aLength, - PRBool aIs2b, PRBool aIsExistingTextRun); + void SetupBreakSinksForTextRun(gfxTextRun* aTextRun, PRBool aIsExistingTextRun); PRBool StylesMatchForTextRun(nsIFrame* aFrame1, nsIFrame* aFrame2); @@ -851,103 +1003,6 @@ ExpandBuffer(PRUnichar* aDest, PRUint8* aSrc, PRUint32 aCount) return aDest; } -static void* -TransformTextToBuffer(nsTextFrame* aFrame, PRInt32 aContentLength, - void* aBuffer, PRInt32 aCharSize, gfxSkipCharsBuilder* aBuilder, - PRPackedBool* aIncomingWhitespace) -{ - const nsTextFragment* frag = aFrame->GetContent()->GetText(); - PRInt32 contentStart = aFrame->GetContentOffset(); - PRBool compressWhitespace = !aFrame->GetStyleText()->WhiteSpaceIsSignificant(); - PRUint32 analysisFlags; - - if (frag->Is2b()) { - NS_ASSERTION(aCharSize == 2, "Wrong size buffer!"); - return nsTextFrameUtils::TransformText( - frag->Get2b() + contentStart, aContentLength, NS_STATIC_CAST(PRUnichar*, aBuffer), - compressWhitespace, aIncomingWhitespace, aBuilder, &analysisFlags); - } else { - if (aCharSize == 2) { - // Need to expand the text. First transform it into a temporary buffer, - // then expand. - nsAutoTArray tempBuf; - if (!tempBuf.AppendElements(aContentLength)) - return nsnull; - PRUint8* end = nsTextFrameUtils::TransformText( - NS_REINTERPRET_CAST(const PRUint8*, frag->Get1b()) + contentStart, aContentLength, - tempBuf.Elements(), compressWhitespace, aIncomingWhitespace, aBuilder, &analysisFlags); - return ExpandBuffer(NS_STATIC_CAST(PRUnichar*, aBuffer), - tempBuf.Elements(), end - tempBuf.Elements()); - } else { - return nsTextFrameUtils::TransformText( - NS_REINTERPRET_CAST(const PRUint8*, frag->Get1b()) + contentStart, aContentLength, - NS_STATIC_CAST(PRUint8*, aBuffer), - compressWhitespace, aIncomingWhitespace, aBuilder, &analysisFlags); - } - } -} - -static void -ReconstructTextForRun(gfxTextRun* aTextRun, PRBool aRememberText, - BuildTextRunsScanner* aSetupBreaks, - PRPackedBool* aIncomingWhitespace) -{ - gfxSkipCharsBuilder builder; - nsAutoTArray buffer; - PRUint32 charSize = (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) ? 1 : 2; - PRInt32 length; - void* bufEnd; - nsTextFrame* f; - - if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - f = NS_STATIC_CAST(nsTextFrame*, aTextRun->GetUserData()); - length = f->GetContentLength(); - if (!buffer.AppendElements(length*charSize)) - return; - bufEnd = TransformTextToBuffer(f, length, buffer.Elements(), charSize, &builder, - aIncomingWhitespace); - if (!bufEnd) - return; - } else { - TextRunUserData* userData = NS_STATIC_CAST(TextRunUserData*, aTextRun->GetUserData()); - length = 0; - PRInt32 i; - for (i = 0; i < userData->mMappedFlowCount; ++i) { - TextRunMappedFlow* flow = &userData->mMappedFlows[i]; - length += flow->mContentLength; - } - if (!buffer.AppendElements(length*charSize)) - return; - - bufEnd = buffer.Elements(); - for (i = 0; i < userData->mMappedFlowCount; ++i) { - TextRunMappedFlow* flow = &userData->mMappedFlows[i]; - bufEnd = TransformTextToBuffer(flow->mStartFrame, flow->mContentLength, bufEnd, - charSize, &builder, aIncomingWhitespace); - if (!bufEnd) - return; - } - f = userData->mMappedFlows[0].mStartFrame; - } - PRUint32 transformedLength = NS_STATIC_CAST(PRUint8*, bufEnd) - buffer.Elements(); - if (charSize == 2) { - transformedLength >>= 1; - } - - if (aRememberText) { - if (charSize == 2) { - aTextRun->RememberText(NS_REINTERPRET_CAST(PRUnichar*, buffer.Elements()), transformedLength); - } else { - aTextRun->RememberText(buffer.Elements(), transformedLength); - } - } - - if (aSetupBreaks) { - aSetupBreaks->SetupBreakSinksForTextRun(aTextRun, buffer.Elements(), transformedLength, - charSize == 2, PR_TRUE); - } -} - /** * This gets called when we need to make a text run for the current list of * frames. @@ -967,8 +1022,9 @@ void BuildTextRunsScanner::FlushFrames(PRBool aFlushLineBreaks) // Feed this run's text into the linebreaker to provide context. This also // updates mTrimNextRunLeadingWhitespace appropriately. - ReconstructTextForRun(mCurrentFramesAllSameTextRun, PR_FALSE, this, - &mTrimNextRunLeadingWhitespace); + SetupBreakSinksForTextRun(mCurrentFramesAllSameTextRun, PR_TRUE); + mTrimNextRunLeadingWhitespace = + (mCurrentFramesAllSameTextRun->GetFlags() & nsTextFrameUtils::TEXT_TRAILING_WHITESPACE) != 0; } else { nsAutoTArray buffer; if (!buffer.AppendElements(mMaxTextLength*(mDoubleByteText ? 2 : 1))) @@ -1115,15 +1171,6 @@ static nscoord StyleToCoord(const nsStyleCoord& aCoord) } } -static void -DestroyUserData(void* aUserData) -{ - TextRunUserData* userData = NS_STATIC_CAST(TextRunUserData*, aUserData); - if (userData) { - nsMemory::Free(userData); - } -} - nsTextFrame* BuildTextRunsScanner::GetNextBreakBeforeFrame(PRUint32* aIndex) { @@ -1164,12 +1211,24 @@ GetFontGroupForFrame(nsIFrame* aFrame) } static gfxTextRun* -GetSpecialString(gfxFontGroup* aFontGroup, gfxFontGroup::SpecialString aSpecial, - gfxTextRun* aTextRun) +GetHyphenTextRun(gfxTextRun* aTextRun, nsIRenderingContext* aRefContext) { - if (!aFontGroup) - return nsnull; - return aFontGroup->GetSpecialStringTextRun(aSpecial, aTextRun); + gfxContext* ctx = NS_STATIC_CAST(gfxContext*, + aRefContext->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT)); + gfxFontGroup* fontGroup = aTextRun->GetFontGroup(); + PRUint32 flags = gfxFontGroup::TEXT_IS_PERSISTENT; + + static const PRUnichar unicodeHyphen = 0x2010; + gfxTextRun* textRun = + gfxGlobalTextRunCache::GetTextRun(&unicodeHyphen, 1, fontGroup, ctx, + aTextRun->GetAppUnitsPerDevUnit(), flags); + if (textRun && textRun->CountMissingGlyphs() == 0) + return textRun; + + static const PRUint8 dash = '-'; + return gfxGlobalTextRunCache::GetTextRun(&dash, 1, fontGroup, ctx, + aTextRun->GetAppUnitsPerDevUnit(), + flags); } static gfxFont::Metrics @@ -1193,7 +1252,6 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) PRBool anyTextTransformStyle = PR_FALSE; nsIContent* lastContent = nsnull; PRInt32 endOfLastContent = 0; - PRBool anyMixedStyleFlows = PR_FALSE; PRUint32 textFlags = gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX; if (mCurrentRunTrimLeadingWhitespace) { @@ -1265,7 +1323,6 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) contentStart = PR_MAX(contentStart, endOfLastContent); if (contentStart >= contentEnd) continue; - anyMixedStyleFlows = PR_TRUE; userData->mMappedFlows[finalMappedFlowCount - 1].mContentLength += contentLength; } else { TextRunMappedFlow* newFlow = &userData->mMappedFlows[finalMappedFlowCount]; @@ -1371,11 +1428,11 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) // Setup factory chain nsAutoPtr transformingFactory; if (anySmallcapsStyle) { - transformingFactory = new nsFontVariantTextRunFactory(fontGroup); + transformingFactory = new nsFontVariantTextRunFactory(); } if (anyTextTransformStyle) { transformingFactory = - new nsCaseTransformTextRunFactory(fontGroup, transformingFactory.forget()); + new nsCaseTransformTextRunFactory(transformingFactory.forget()); } nsTArray styles; if (transformingFactory) { @@ -1397,12 +1454,12 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) if (textFlags & nsTextFrameUtils::TEXT_HAS_SHY) { textFlags |= gfxTextRunFactory::TEXT_ENABLE_HYPHEN_BREAKS; } - if (!(textFlags & nsTextFrameUtils::TEXT_HAS_NON_ASCII)) { - textFlags |= gfxTextRunFactory::TEXT_IS_ASCII; - } if (mBidiEnabled && (NS_GET_EMBEDDING_LEVEL(firstFrame) & 1)) { textFlags |= gfxTextRunFactory::TEXT_IS_RTL; } + if (mTrimNextRunLeadingWhitespace) { + textFlags |= nsTextFrameUtils::TEXT_TRAILING_WHITESPACE; + } gfxSkipChars skipChars; skipChars.TakeFrom(&builder); @@ -1420,59 +1477,48 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) } gfxTextRunFactory::Parameters params = - { mContext, finalUserData, firstFrame->GetStyleVisibility()->mLangGroup, &skipChars, + { mContext, finalUserData, &skipChars, textBreakPoints.Elements(), nextBreakIndex, - firstFrame->PresContext()->AppUnitsPerDevPixel(), textFlags }; + firstFrame->PresContext()->AppUnitsPerDevPixel() }; gfxTextRun* textRun; if (mDoubleByteText) { - if (textFlags & gfxTextRunFactory::TEXT_IS_ASCII) { - NS_WARNING("Hmm ... why are we taking the Unicode path when the text is all ASCII?"); - } const PRUnichar* text = NS_STATIC_CAST(const PRUnichar*, textPtr); if (transformingFactory) { textRun = transformingFactory->MakeTextRun(text, transformedLength, ¶ms, - styles.Elements()); + fontGroup, textFlags, styles.Elements()); if (textRun) { transformingFactory.forget(); } } else { - textRun = fontGroup->MakeTextRun(text, transformedLength, ¶ms); + textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, textFlags); } if (!textRun) { DestroyUserData(userData); return; } - if (anyMixedStyleFlows) { - // Make sure we're not asked to recover the text, it's too hard to do later. - textRun->RememberText(text, transformedLength); - } } else { const PRUint8* text = NS_STATIC_CAST(const PRUint8*, textPtr); + textFlags |= gfxFontGroup::TEXT_IS_8BIT; if (transformingFactory) { textRun = transformingFactory->MakeTextRun(text, transformedLength, ¶ms, - styles.Elements()); + fontGroup, textFlags, styles.Elements()); if (textRun) { transformingFactory.forget(); } } else { - textRun = fontGroup->MakeTextRun(text, transformedLength, ¶ms); + textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, textFlags); } if (!textRun) { DestroyUserData(userData); return; } - if (anyMixedStyleFlows) { - // Make sure we're not asked to recover the text, it's too hard to do later. - textRun->RememberText(text, transformedLength); - } } // We have to set these up after we've created the textrun, because // the breaks may be stored in the textrun during this very call. // This is a bit annoying because it requires another loop over the frames // making up the textrun, but I don't see a way to avoid this. - SetupBreakSinksForTextRun(textRun, textPtr, transformedLength, mDoubleByteText, - PR_FALSE); + SetupBreakSinksForTextRun(textRun, PR_FALSE); // Actually wipe out the textruns associated with the mapped frames and associate // those frames with this text run. @@ -1480,8 +1526,8 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) } void -BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun, const void* aText, PRUint32 aLength, - PRBool aIs2b, PRBool aIsExistingTextRun) +BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun, + PRBool aIsExistingTextRun) { // textruns have uniform language nsIAtom* lang = mMappedFlows[0].mStartFrame->GetStyleVisibility()->mLangGroup; @@ -1495,7 +1541,8 @@ BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun, const void PRUint32 offset = mappedFlow->mTransformedTextOffset; PRUint32 length = - (i == mMappedFlows.Length() - 1 ? aLength : mMappedFlows[i + 1].mTransformedTextOffset) + (i == mMappedFlows.Length() - 1 ? aTextRun->GetLength() + : mMappedFlows[i + 1].mTransformedTextOffset) - offset; PRUint32 flags = 0; @@ -1509,11 +1556,11 @@ BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun, const void // If length is zero and BREAK_WHITESPACE is active, this will notify // the linebreaker to insert a break opportunity before the next character. // Thus runs of entirely-skipped whitespace can still induce breaks. - if (aIs2b) { - mLineBreaker.AppendText(lang, NS_STATIC_CAST(const PRUnichar*, aText) + offset, + if (aTextRun->GetFlags() & gfxFontGroup::TEXT_IS_8BIT) { + mLineBreaker.AppendText(lang, aTextRun->GetText8Bit() + offset, length, flags, *breakSink); } else { - mLineBreaker.AppendText(lang, NS_STATIC_CAST(const PRUint8*, aText) + offset, + mLineBreaker.AppendText(lang, aTextRun->GetTextUnicode() + offset, length, flags, *breakSink); } } @@ -1561,22 +1608,35 @@ BuildTextRunsScanner::AssignTextRun(gfxTextRun* aTextRun) } } +static already_AddRefed +GetReferenceRenderingContext(nsTextFrame* aTextFrame, nsIRenderingContext* aRC) +{ + if (aRC) { + NS_ADDREF(aRC); + return aRC; + } + + nsIRenderingContext* result; + nsresult rv = aTextFrame->PresContext()->PresShell()-> + CreateRenderingContext(aTextFrame, &result); + if (NS_FAILED(rv)) + return nsnull; + return result; +} + gfxSkipCharsIterator nsTextFrame::EnsureTextRun(nsIRenderingContext* aRC, nsBlockFrame* aBlock, const nsLineList::iterator* aLine, PRUint32* aFlowEndInTextRun) { - if (!mTextRun) { - if (!aRC) { - nsCOMPtr rendContext; - nsresult rv = PresContext()->PresShell()-> - CreateRenderingContext(this, getter_AddRefs(rendContext)); - if (NS_SUCCEEDED(rv)) { - BuildTextRuns(rendContext, this, aBlock, aLine); - } - } else { - BuildTextRuns(aRC, this, aBlock, aLine); - } + if (mTextRun) { + if (mTextRun->GetExpirationState()->IsTracked()) { + gTextRuns->MarkUsed(mTextRun); + } + } else { + nsCOMPtr rendContext = + GetReferenceRenderingContext(this, aRC); + BuildTextRuns(rendContext, this, aBlock, aLine); if (!mTextRun) { // A text run was not constructed for this frame. This is bad. The caller // will check mTextRun. @@ -1802,12 +1862,6 @@ public: // Call this after construction if you're not going to reflow the text void InitializeForDisplay(PRBool aTrimAfter); - virtual void ForceRememberText() { - PRPackedBool incomingWhitespace = - (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_INCOMING_WHITESPACE) != 0; - ReconstructTextForRun(mTextRun, PR_TRUE, nsnull, &incomingWhitespace); - } - virtual void GetSpacing(PRUint32 aStart, PRUint32 aLength, Spacing* aSpacing); virtual gfxFloat GetHyphenWidth(); virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength, @@ -2000,12 +2054,8 @@ PropertyProvider::GetSpacing(PRUint32 aStart, PRUint32 aLength, // for tabs, and how many. // ComputeTabSpaceCount takes transformed string offsets. PRUint8* tabSpaceList = ComputeTabSpaceCount(aStart, aLength); - gfxTextRun* spaceTextRun = - GetSpecialString(GetFontGroup(), gfxFontGroup::STRING_SPACE, mTextRun); - gfxFloat spaceWidth = mLetterSpacing + mWordSpacing; - if (spaceTextRun) { - spaceWidth += spaceTextRun->GetAdvanceWidth(0, spaceTextRun->GetLength(), nsnull); - } + gfxFloat spaceWidth = mLetterSpacing + mWordSpacing + + mTextRun->GetFontGroup()->GetFontAt(0)->GetMetrics().spaceWidth*mTextRun->GetAppUnitsPerDevUnit(); for (index = 0; index < aLength; ++index) { PRInt32 tabSpaces = tabSpaceList[index]; aSpacing[index].mAfter += spaceWidth*tabSpaces; @@ -2064,8 +2114,8 @@ gfxFloat PropertyProvider::GetHyphenWidth() { if (mHyphenWidth < 0) { - gfxTextRun* hyphenTextRun = - GetSpecialString(GetFontGroup(), gfxFontGroup::STRING_HYPHEN, mTextRun); + nsCOMPtr rc = GetReferenceRenderingContext(mFrame, nsnull); + gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, rc); mHyphenWidth = mLetterSpacing; if (hyphenTextRun) { mHyphenWidth += hyphenTextRun->GetAdvanceWidth(0, hyphenTextRun->GetLength(), nsnull); @@ -2170,11 +2220,11 @@ PropertyProvider::SetupJustificationSpacing() mTextRun->GetAdvanceWidth(mStart.GetSkippedOffset(), GetSkippedDistance(mStart, realEnd), this); if (mFrame->GetStateBits() & TEXT_HYPHEN_BREAK) { - gfxTextRun* specialTextRun = - GetSpecialString(GetFontGroup(), gfxFontGroup::STRING_HYPHEN, mTextRun); - if (specialTextRun) { + nsCOMPtr rc = GetReferenceRenderingContext(mFrame, nsnull); + gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, rc); + if (hyphenTextRun) { naturalWidth += - specialTextRun->GetAdvanceWidth(0, specialTextRun->GetLength(), nsnull); + hyphenTextRun->GetAdvanceWidth(0, hyphenTextRun->GetLength(), nsnull); } } gfxFloat totalJustificationSpace = mFrame->GetSize().width - naturalWidth; @@ -3042,18 +3092,6 @@ nsTextFrame::GetLastContinuation() const return lastInFlow; } -static void -ClearAllTextRunReferences(nsTextFrame* aFrame, gfxTextRun* aTextRun) -{ - aFrame->RemoveStateBits(TEXT_IS_RUN_OWNER); - while (aFrame) { - if (aFrame->GetTextRun() != aTextRun) - break; - aFrame->SetTextRun(nsnull); - aFrame = NS_STATIC_CAST(nsTextFrame*, aFrame->GetNextContinuation()); - } -} - void nsTextFrame::ClearTextRun() { @@ -3063,21 +3101,22 @@ nsTextFrame::ClearTextRun() if (!textRun || !(GetStateBits() & TEXT_IS_RUN_OWNER)) return; - // Kill all references to the textrun. It could be referenced by any of its - // owners, and all their in-flows. - if (textRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - nsIFrame* firstInFlow = NS_STATIC_CAST(nsIFrame*, textRun->GetUserData()); - ClearAllTextRunReferences(NS_STATIC_CAST(nsTextFrame*, firstInFlow), textRun); - } else { - TextRunUserData* userData = - NS_STATIC_CAST(TextRunUserData*, textRun->GetUserData()); - PRInt32 i; - for (i = 0; i < userData->mMappedFlowCount; ++i) { - ClearAllTextRunReferences(userData->mMappedFlows[i].mStartFrame, textRun); + UnhookTextRunFromFrames(textRun); + if (textRun->GetFlags() & gfxFontGroup::TEXT_IS_PERSISTENT) { + // the textrun's text may be referencing a DOM node that's changing, + // or that will change, so we'd better kill this textrun now. + if (textRun->GetExpirationState()->IsTracked()) { + gTextRuns->RemoveFromCache(textRun); } - DestroyUserData(userData); + delete textRun; + return; + } + + // If it's not tracked (i.e. in the cache), then delete it now. + // Otherwise it stays alive in case it gets hit in the cache. + if (!textRun->GetExpirationState()->IsTracked()) { + delete textRun; } - delete textRun; } NS_IMETHODIMP @@ -3619,8 +3658,10 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx, if (hyphenWidth) { // Draw the hyphen gfxFloat hyphenBaselineX = aFramePt.x + xOffset + mTextRun->GetDirection()*advance; - gfxTextRun* hyphenTextRun = - GetSpecialString(aProvider.GetFontGroup(), gfxFontGroup::STRING_HYPHEN, mTextRun); + // Get a reference rendering context because aCtx might not have the + // reference matrix currently set + nsCOMPtr rc = GetReferenceRenderingContext(this, nsnull); + gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, rc); if (hyphenTextRun) { hyphenTextRun->Draw(aCtx, gfxPoint(hyphenBaselineX, aTextBaselinePt.y), 0, hyphenTextRun->GetLength(), &aDirtyRect, nsnull, nsnull); @@ -3771,8 +3812,8 @@ nsTextFrame::PaintText(nsIRenderingContext* aRenderingContext, nsPoint aPt, &dirtyRect, &provider, needAdvanceWidth); if (GetStateBits() & TEXT_HYPHEN_BREAK) { gfxFloat hyphenBaselineX = textBaselinePt.x + mTextRun->GetDirection()*advanceWidth; - gfxTextRun* hyphenTextRun = - GetSpecialString(provider.GetFontGroup(), gfxFontGroup::STRING_HYPHEN, mTextRun); + nsCOMPtr rc = GetReferenceRenderingContext(this, nsnull); + gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, rc); if (hyphenTextRun) { hyphenTextRun->Draw(ctx, gfxPoint(hyphenBaselineX, textBaselinePt.y), 0, hyphenTextRun->GetLength(), &dirtyRect, nsnull, nsnull); @@ -4541,36 +4582,31 @@ nsTextFrame::ComputeSize(nsIRenderingContext *aRenderingContext, } static void -AddCharToMetrics(gfxFloat aWidth, PropertyProvider* aProvider, - gfxFontGroup::SpecialString aSpecial, gfxTextRun* aTextRun, +AddCharToMetrics(gfxTextRun* aCharTextRun, gfxTextRun* aBaseTextRun, gfxTextRun::Metrics* aMetrics, PRBool aTightBoundingBox) { gfxRect charRect; + // assume char does not overflow font metrics!!! + gfxFloat width = aCharTextRun->GetAdvanceWidth(0, aCharTextRun->GetLength(), nsnull); if (aTightBoundingBox) { - gfxTextRun* specialTextRun = - GetSpecialString(aProvider->GetFontGroup(), aSpecial, aTextRun); - gfxTextRun::Metrics charMetrics; - if (specialTextRun) { - charMetrics = - specialTextRun->MeasureText(0, specialTextRun->GetLength(), PR_TRUE, nsnull); - } + gfxTextRun::Metrics charMetrics = + aCharTextRun->MeasureText(0, aCharTextRun->GetLength(), PR_TRUE, nsnull); charRect = charMetrics.mBoundingBox; } else { - // assume char does not overflow font metrics!!! - charRect = gfxRect(0, -aMetrics->mAscent, aWidth, + charRect = gfxRect(0, -aMetrics->mAscent, width, aMetrics->mAscent + aMetrics->mDescent); } - if (aTextRun->IsRightToLeft()) { + if (aBaseTextRun->IsRightToLeft()) { // Char comes before text, so the bounding box is moved to the // right by aWidth - aMetrics->mBoundingBox.MoveBy(gfxPoint(aWidth, 0)); + aMetrics->mBoundingBox.MoveBy(gfxPoint(width, 0)); } else { // char is moved to the right by mAdvanceWidth - charRect.MoveBy(gfxPoint(aMetrics->mAdvanceWidth, 0)); + charRect.MoveBy(gfxPoint(width, 0)); } aMetrics->mBoundingBox = aMetrics->mBoundingBox.Union(charRect); - aMetrics->mAdvanceWidth += aWidth; + aMetrics->mAdvanceWidth += width; } NS_IMETHODIMP @@ -4789,7 +4825,8 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, } if (usedHyphenation) { // Fix up metrics to include hyphen - AddCharToMetrics(provider.GetHyphenWidth(), &provider, gfxFontGroup::STRING_HYPHEN, + gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, aReflowState.rendContext); + AddCharToMetrics(hyphenTextRun, mTextRun, &textMetrics, needTightBoundingBox); AddStateBits(TEXT_HYPHEN_BREAK); } @@ -4981,7 +5018,6 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext, PRUint32 trimmedEnd = iter.ConvertOriginalToSkipped(trimmed.mStart + trimmed.mLength); const nsStyleText* textStyle = GetStyleText(); gfxFloat delta = 0; - PropertyProvider provider(mTextRun, textStyle, frag, this, iter, mContentLength); if (GetStateBits() & TEXT_TRIMMED_TRAILING_WHITESPACE) { aLastCharIsJustifiable = PR_TRUE; @@ -4989,6 +5025,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext, gfxSkipCharsIterator end = iter; PRUint32 endOffset = end.ConvertOriginalToSkipped(mContentOffset + mContentLength); if (trimmedEnd < endOffset) { + PropertyProvider provider(mTextRun, textStyle, frag, this, iter, mContentLength); delta = mTextRun->GetAdvanceWidth(trimmedEnd, endOffset - trimmedEnd, &provider); // non-compressed whitespace being skipped at end of line -> justifiable // XXX should we actually *count* justifiable characters that should be @@ -5000,6 +5037,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext, if (!aLastCharIsJustifiable && NS_STYLE_TEXT_ALIGN_JUSTIFY == textStyle->mTextAlign) { // Check if any character in the last cluster is justifiable + PropertyProvider provider(mTextRun, textStyle, frag, this, iter, mContentLength); PRBool isCJK = IsChineseJapaneseLangGroup(this); gfxSkipCharsIterator justificationEnd(iter); provider.FindEndOfJustificationRange(&justificationEnd); @@ -5015,7 +5053,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext, gfxFloat advanceDelta; mTextRun->SetLineBreaks(trimmedStart, trimmedEnd - trimmedStart, (GetStateBits() & TEXT_START_OF_LINE) != 0, PR_TRUE, - &provider, &advanceDelta); + &advanceDelta); // aDeltaWidth is *subtracted* from our width. // If advanceDelta is positive then setting the line break made us longer, diff --git a/layout/generic/nsTextFrameUtils.cpp b/layout/generic/nsTextFrameUtils.cpp index 0911edff545..55cc02e41fc 100644 --- a/layout/generic/nsTextFrameUtils.cpp +++ b/layout/generic/nsTextFrameUtils.cpp @@ -103,8 +103,7 @@ nsTextFrameUtils::TransformText(const PRUnichar* aText, PRUint32 aLength, gfxSkipCharsBuilder* aSkipChars, PRUint32* aAnalysisFlags) { - // We're just going to assume this! - PRUint32 flags = TEXT_HAS_NON_ASCII; + PRUint32 flags = 0; PRUnichar* outputStart = aOutput; if (!aCompressWhitespace) { @@ -123,8 +122,6 @@ nsTextFrameUtils::TransformText(const PRUnichar* aText, PRUint32 aLength, if (ch == CH_NBSP) { ch = ' '; flags |= TEXT_WAS_TRANSFORMED; - } else if (IS_SURROGATE(ch)) { - flags |= gfxTextRunFactory::TEXT_HAS_SURROGATES; } *aOutput++ = ch; } @@ -161,8 +158,6 @@ nsTextFrameUtils::TransformText(const PRUnichar* aText, PRUint32 aLength, if (ch == CH_NBSP) { ch = ' '; flags |= TEXT_WAS_TRANSFORMED; - } else if (IS_SURROGATE(ch)) { - flags |= gfxTextRunFactory::TEXT_HAS_SURROGATES; } *aOutput++ = ch; aSkipChars->KeepChar(); @@ -199,7 +194,6 @@ nsTextFrameUtils::TransformText(const PRUint8* aText, PRUint32 aLength, PRUint32* aAnalysisFlags) { PRUint32 flags = 0; - PRUint8 allBits = 0; PRUint8* outputStart = aOutput; if (!aCompressWhitespace) { @@ -207,7 +201,6 @@ nsTextFrameUtils::TransformText(const PRUint8* aText, PRUint32 aLength, PRUint32 i; for (i = 0; i < aLength; ++i) { PRUint8 ch = *aText++; - allBits |= ch; if (ch == '\t') { flags |= TEXT_HAS_TAB|TEXT_WAS_TRANSFORMED; aSkipChars->KeepChar(); @@ -229,7 +222,6 @@ nsTextFrameUtils::TransformText(const PRUint8* aText, PRUint32 aLength, PRUint32 i; for (i = 0; i < aLength; ++i) { PRUint8 ch = *aText++; - allBits |= ch; PRBool nowInWhitespace = ch == ' ' || ch == '\t' || ch == '\n' || ch == '\f'; if (!nowInWhitespace) { if (IsDiscardable(ch, &flags)) { @@ -262,9 +254,6 @@ nsTextFrameUtils::TransformText(const PRUint8* aText, PRUint32 aLength, if (outputStart + aLength != aOutput) { flags |= TEXT_WAS_TRANSFORMED; } - if (allBits & 0x80) { - flags |= TEXT_HAS_NON_ASCII; - } *aAnalysisFlags = flags; return aOutput; } diff --git a/layout/generic/nsTextFrameUtils.h b/layout/generic/nsTextFrameUtils.h index 0b94f0a1669..201506aa1b2 100644 --- a/layout/generic/nsTextFrameUtils.h +++ b/layout/generic/nsTextFrameUtils.h @@ -40,6 +40,7 @@ #include "gfxFont.h" #include "gfxSkipChars.h" +#include "gfxTextRunCache.h" #include "nsTextFragment.h" #define BIG_TEXT_NODE_SIZE 4096 @@ -54,13 +55,14 @@ public: TEXT_HAS_TAB = 0x010000, // the original text has at least one soft hyphen character TEXT_HAS_SHY = 0x020000, - TEXT_HAS_NON_ASCII = 0x040000, - TEXT_WAS_TRANSFORMED = 0x080000, + TEXT_WAS_TRANSFORMED = 0x040000, // The following flags are set by nsTextFrame TEXT_IS_SIMPLE_FLOW = 0x100000, - TEXT_INCOMING_WHITESPACE = 0x200000 + TEXT_INCOMING_WHITESPACE = 0x200000, + TEXT_TRAILING_WHITESPACE = 0x400000, + TEXT_IS_UNCACHED = 0x800000 }; static PRBool @@ -86,6 +88,9 @@ public: * @param aCompressWhitespace runs of consecutive whitespace (spaces not * followed by a diacritical mark, tabs, and newlines) are compressed to a * single space character. + * @param aIncomingWhitespace a flag indicating whether there was whitespace + * preceding this text. We set it to indicate if there's whitespace + * preceding the end of this text. */ static PRUnichar* TransformText(const PRUnichar* aText, PRUint32 aLength, PRUnichar* aOutput, @@ -132,7 +137,7 @@ public: PRInt32 aPosition, PRInt32 aDirection, PRBool aBreakBeforePunctuation, PRBool aBreakAfterPunctuation, - PRBool* aWordIsWhitespace); + PRBool* aWordIsWhitespace); }; class nsSkipCharsRunIterator { diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index 1f015a66908..f48c19c9372 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -54,13 +54,13 @@ */ class nsTransformedTextRun : public gfxTextRun { public: - nsTransformedTextRun(gfxTextRunFactory::Parameters* aParams, + nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams, nsTransformingTextRunFactory* aFactory, + gfxFontGroup* aFontGroup, const PRUnichar* aString, PRUint32 aLength, - nsStyleContext** aStyles) - : gfxTextRun(aParams, aLength), mString(aString, aLength), - mFactory(aFactory), mRefContext(aParams->mContext), - mLangGroup(aParams->mLangGroup) + const PRUint32 aFlags, nsStyleContext** aStyles) + : gfxTextRun(aParams, aString, aLength, aFontGroup, aFlags), + mFactory(aFactory), mRefContext(aParams->mContext) { PRUint32 i; for (i = 0; i < aLength; ++i) { @@ -80,13 +80,10 @@ public: } virtual PRBool SetLineBreaks(PRUint32 aStart, PRUint32 aLength, PRBool aLineBreakBefore, PRBool aLineBreakAfter, - PropertyProvider* aProvider, gfxFloat* aAdvanceWidthDelta); - nsString mString; nsAutoPtr mFactory; nsRefPtr mRefContext; - nsCOMPtr mLangGroup; nsTArray mLineBreaks; nsTArray > mStyles; }; @@ -94,7 +91,6 @@ public: PRBool nsTransformedTextRun::SetLineBreaks(PRUint32 aStart, PRUint32 aLength, PRBool aLineBreakBefore, PRBool aLineBreakAfter, - PropertyProvider* aProvider, gfxFloat* aAdvanceWidthDelta) { nsTArray newBreaks; @@ -135,21 +131,22 @@ nsTransformedTextRun::SetLineBreaks(PRUint32 aStart, PRUint32 aLength, newBreaks.AppendElements(mLineBreaks.Elements() + i, mLineBreaks.Length() - i); mLineBreaks.SwapElements(newBreaks); - gfxFloat currentAdvance = GetAdvanceWidth(aStart, aLength, aProvider); + gfxFloat currentAdvance = GetAdvanceWidth(aStart, aLength, nsnull); mFactory->RebuildTextRun(this); if (aAdvanceWidthDelta) { - *aAdvanceWidthDelta = GetAdvanceWidth(aStart, aLength, aProvider) - currentAdvance; + *aAdvanceWidthDelta = GetAdvanceWidth(aStart, aLength, nsnull) - currentAdvance; } return PR_TRUE; } gfxTextRun* nsTransformingTextRunFactory::MakeTextRun(const PRUnichar* aString, PRUint32 aLength, - gfxTextRunFactory::Parameters* aParams, + const gfxTextRunFactory::Parameters* aParams, + gfxFontGroup* aFontGroup, PRUint32 aFlags, nsStyleContext** aStyles) { nsTransformedTextRun* textRun = - new nsTransformedTextRun(aParams, this, aString, aLength, aStyles); + new nsTransformedTextRun(aParams, this, aFontGroup, aString, aLength, aFlags, aStyles); if (!textRun) return nsnull; RebuildTextRun(textRun); @@ -158,15 +155,16 @@ nsTransformingTextRunFactory::MakeTextRun(const PRUnichar* aString, PRUint32 aLe gfxTextRun* nsTransformingTextRunFactory::MakeTextRun(const PRUint8* aString, PRUint32 aLength, - gfxTextRunFactory::Parameters* aParams, + const gfxTextRunFactory::Parameters* aParams, + gfxFontGroup* aFontGroup, PRUint32 aFlags, nsStyleContext** aStyles) { // We'll only have a Unicode code path to minimize the amount of code needed // for these rarely used features NS_ConvertASCIItoUTF16 unicodeString(NS_REINTERPRET_CAST(const char*, aString), aLength); - gfxTextRunFactory::Parameters params = *aParams; - params.mFlags &= ~gfxTextRunFactory::TEXT_IS_PERSISTENT; - return MakeTextRun(unicodeString.get(), aLength, ¶ms, aStyles); + return MakeTextRun(unicodeString.get(), aLength, aParams, aFontGroup, + aFlags & ~(gfxFontGroup::TEXT_IS_PERSISTENT | gfxFontGroup::TEXT_IS_8BIT), + aStyles); } static PRUint32 @@ -301,13 +299,13 @@ MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc, } static gfxTextRunFactory::Parameters -GetParametersForInner(nsTransformedTextRun* aTextRun, - gfxSkipChars* aDummy) +GetParametersForInner(nsTransformedTextRun* aTextRun, PRUint32* aFlags) { gfxTextRunFactory::Parameters params = - { aTextRun->mRefContext, nsnull, aTextRun->mLangGroup, aDummy, - nsnull, nsnull, PRUint32(aTextRun->GetAppUnitsPerDevUnit()), - aTextRun->GetFlags() }; + { aTextRun->mRefContext, nsnull, nsnull, + nsnull, nsnull, PRUint32(aTextRun->GetAppUnitsPerDevUnit()) + }; + *aFlags = aTextRun->GetFlags() & ~gfxFontGroup::TEXT_IS_PERSISTENT; return params; } @@ -318,25 +316,26 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun) if (!converter) return; - gfxFontStyle fontStyle = *mFontGroup->GetStyle(); + gfxFontGroup* fontGroup = aTextRun->GetFontGroup(); + gfxFontStyle fontStyle = *fontGroup->GetStyle(); fontStyle.size *= 0.8; - nsRefPtr smallFont = mFontGroup->Copy(&fontStyle); + nsRefPtr smallFont = fontGroup->Copy(&fontStyle); if (!smallFont) return; - gfxSkipChars dummy; - gfxTextRunFactory::Parameters innerParams = GetParametersForInner(aTextRun, &dummy); + PRUint32 flags; + gfxTextRunFactory::Parameters innerParams = GetParametersForInner(aTextRun, &flags); PRUint32 length = aTextRun->GetLength(); - const PRUnichar* str = aTextRun->mString.BeginReading(); + const PRUnichar* str = aTextRun->GetTextUnicode(); nsRefPtr* styles = aTextRun->mStyles.Elements(); // Create a textrun so we can check cluster-start properties nsAutoPtr inner; - inner = mFontGroup->MakeTextRun(str, length, &innerParams); + inner = fontGroup->MakeTextRun(str, length, &innerParams, flags); if (!inner) return; - nsCaseTransformTextRunFactory uppercaseFactory(smallFont, nsnull, PR_TRUE); + nsCaseTransformTextRunFactory uppercaseFactory(nsnull, PR_TRUE); aTextRun->ResetGlyphRuns(); @@ -379,9 +378,11 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun) innerParams.mInitialBreakCount = lineBreakBeforeArray.Length(); if (runIsLowercase) { child = uppercaseFactory.MakeTextRun(str + runStart, i - runStart, - &innerParams, styleArray.Elements()); + &innerParams, smallFont, flags, + styleArray.Elements()); } else { - child = mFontGroup->MakeTextRun(str + runStart, i - runStart, &innerParams); + child = fontGroup-> + MakeTextRun(str + runStart, i - runStart, &innerParams, flags); } if (!child) return; @@ -419,7 +420,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun) return; PRUint32 length = aTextRun->GetLength(); - const PRUnichar* str = aTextRun->mString.BeginReading(); + const PRUnichar* str = aTextRun->GetTextUnicode(); nsRefPtr* styles = aTextRun->mStyles.Elements(); nsAutoString convertedString; @@ -491,8 +492,9 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun) NS_ASSERTION(nextLineBreak == aTextRun->mLineBreaks.Length(), "lost track of line breaks somehow"); - gfxSkipChars dummy; - gfxTextRunFactory::Parameters innerParams = GetParametersForInner(aTextRun, &dummy); + PRUint32 flags; + gfxTextRunFactory::Parameters innerParams = GetParametersForInner(aTextRun, &flags); + gfxFontGroup* fontGroup = aTextRun->GetFontGroup(); nsAutoPtr child; // Setup actual line break data for child (which may affect shaping) @@ -501,10 +503,11 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun) if (mInnerTransformingTextRunFactory) { child = mInnerTransformingTextRunFactory->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), - &innerParams, styleArray.Elements()); + &innerParams, fontGroup, flags, styleArray.Elements()); } else { - child = mFontGroup->MakeTextRun( - convertedString.BeginReading(), convertedString.Length(), &innerParams); + child = fontGroup->MakeTextRun( + convertedString.BeginReading(), convertedString.Length(), &innerParams, + flags); } if (!child) return; diff --git a/layout/generic/nsTextRunTransformations.h b/layout/generic/nsTextRunTransformations.h index 3d2b78fdc89..5f90bc4fc7b 100644 --- a/layout/generic/nsTextRunTransformations.h +++ b/layout/generic/nsTextRunTransformations.h @@ -49,9 +49,13 @@ public: // Default 8-bit path just transforms to Unicode and takes that path gfxTextRun* MakeTextRun(const PRUint8* aString, PRUint32 aLength, - gfxFontGroup::Parameters* aParams, nsStyleContext** aStyles); + const gfxFontGroup::Parameters* aParams, + gfxFontGroup* aFontGroup, PRUint32 aFlags, + nsStyleContext** aStyles); gfxTextRun* MakeTextRun(const PRUnichar* aString, PRUint32 aLength, - gfxFontGroup::Parameters* aParams, nsStyleContext** aStyles); + const gfxFontGroup::Parameters* aParams, + gfxFontGroup* aFontGroup, PRUint32 aFlags, + nsStyleContext** aStyles); virtual void RebuildTextRun(nsTransformedTextRun* aTextRun) = 0; }; @@ -62,13 +66,7 @@ public: */ class nsFontVariantTextRunFactory : public nsTransformingTextRunFactory { public: - nsFontVariantTextRunFactory(gfxFontGroup* aFontGroup) - : mFontGroup(aFontGroup) {} - virtual void RebuildTextRun(nsTransformedTextRun* aTextRun); - -protected: - nsRefPtr mFontGroup; }; /** @@ -83,17 +81,14 @@ public: // just convert the string to uppercase or lowercase and create the textrun // via the fontgroup. - nsCaseTransformTextRunFactory(gfxFontGroup* aFontGroup, - nsTransformingTextRunFactory* aInnerTransformingTextRunFactory, + nsCaseTransformTextRunFactory(nsTransformingTextRunFactory* aInnerTransformingTextRunFactory, PRBool aAllUppercase = PR_FALSE) - : mFontGroup(aFontGroup), - mInnerTransformingTextRunFactory(aInnerTransformingTextRunFactory), + : mInnerTransformingTextRunFactory(aInnerTransformingTextRunFactory), mAllUppercase(aAllUppercase) {} virtual void RebuildTextRun(nsTransformedTextRun* aTextRun); protected: - nsRefPtr mFontGroup; nsAutoPtr mInnerTransformingTextRunFactory; PRPackedBool mAllUppercase; };