diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 48eb8c2c5c4e..e2275096490b 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -367,6 +367,11 @@ public: TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag, PRBool aTrimAfter); + // Similar to Reflow(), but for use from nsLineLayout + void ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, + nsIRenderingContext* aRenderingContext, PRBool aShouldBlink, + nsHTMLReflowMetrics& aMetrics, nsReflowStatus& aStatus); + protected: virtual ~nsTextFrame(); diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index eb55c304a15a..7f698d207d94 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -6195,12 +6195,38 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, { DO_GLOBAL_REFLOW_COUNT("nsTextFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); + + // XXX If there's no line layout, we shouldn't even have created this + // frame. This may happen if, for example, this is text inside a table + // but not inside a cell. For now, just don't reflow. + if (!aReflowState.mLineLayout) { + ClearMetrics(aMetrics); + aStatus = NS_FRAME_COMPLETE; + return NS_OK; + } + + ReflowText(*aReflowState.mLineLayout, aReflowState.availableWidth, + aReflowState.rendContext, aReflowState.mFlags.mBlinks, + aMetrics, aStatus); + + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); + return NS_OK; +} + +void +nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, + nsIRenderingContext* aRenderingContext, + PRBool aShouldBlink, + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus) +{ #ifdef NOISY_REFLOW ListTag(stdout); - printf(": BeginReflow: availableSize=%d,%d\n", - aReflowState.availableWidth, aReflowState.availableHeight); + printf(": BeginReflow: availableWidth=%d\n", aAvailableWidth); #endif + nsPresContext* presContext = PresContext(); + ///////////////////////////////////////////////////////////////////// // Set up flags and clear out state ///////////////////////////////////////////////////////////////////// @@ -6216,22 +6242,17 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // content; gfxTextRun construction logic will ensure that we take priority. PRInt32 maxContentLength = GetInFlowContentLength(); - // XXX If there's no line layout, we shouldn't even have created this - // frame. This may happen if, for example, this is text inside a table - // but not inside a cell. For now, just don't reflow. We also don't need to - // reflow if there is no content. - if (!aReflowState.mLineLayout || !maxContentLength) { + // We don't need to reflow if there is no content. + if (!maxContentLength) { ClearMetrics(aMetrics); aStatus = NS_FRAME_COMPLETE; - return NS_OK; + return; } - nsLineLayout& lineLayout = *aReflowState.mLineLayout; - - if (aReflowState.mFlags.mBlinks) { + if (aShouldBlink) { if (0 == (mState & TEXT_BLINK_ON)) { mState |= TEXT_BLINK_ON; - nsBlinkTimer::AddBlinkFrame(aPresContext, this); + nsBlinkTimer::AddBlinkFrame(presContext, this); } } else { @@ -6243,14 +6264,14 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, const nsStyleText* textStyle = GetStyleText(); - PRBool atStartOfLine = lineLayout.LineAtStart(); + PRBool atStartOfLine = aLineLayout.LineAtStart(); if (atStartOfLine) { AddStateBits(TEXT_START_OF_LINE); } PRUint32 flowEndInTextRun; - nsIFrame* lineContainer = lineLayout.GetLineContainerFrame(); - gfxContext* ctx = aReflowState.rendContext->ThebesContext(); + nsIFrame* lineContainer = aLineLayout.GetLineContainerFrame(); + gfxContext* ctx = aRenderingContext->ThebesContext(); const nsTextFragment* frag = mContent->GetText(); // DOM offsets of the text range we need to measure, after trimming @@ -6290,21 +6311,21 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, PRBool completedFirstLetter = PR_FALSE; // Layout dependent styles are a problem because we need to reconstruct // the gfxTextRun based on our layout. - if (lineLayout.GetInFirstLetter() || lineLayout.GetInFirstLine()) { - SetLength(maxContentLength, &lineLayout); + if (aLineLayout.GetInFirstLetter() || aLineLayout.GetInFirstLine()) { + SetLength(maxContentLength, &aLineLayout); - if (lineLayout.GetInFirstLetter()) { + if (aLineLayout.GetInFirstLetter()) { // floating first-letter boundaries are significant in textrun // construction, so clear the textrun out every time we hit a first-letter // and have changed our length (which controls the first-letter boundary) ClearTextRun(); // Find the length of the first-letter. We need a textrun for this. gfxSkipCharsIterator iter = - EnsureTextRun(ctx, lineContainer, lineLayout.GetLine(), &flowEndInTextRun); + EnsureTextRun(ctx, lineContainer, aLineLayout.GetLine(), &flowEndInTextRun); if (mTextRun) { PRInt32 firstLetterLength = length; - if (lineLayout.GetFirstLetterStyleOK()) { + if (aLineLayout.GetFirstLetterStyleOK()) { completedFirstLetter = FindFirstLetterRange(frag, mTextRun, offset, iter, &firstLetterLength); if (newLineOffset >= 0) { @@ -6333,7 +6354,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // Change this frame's length to the first-letter length right now // so that when we rebuild the textrun it will be built with the // right first-letter boundary - SetLength(offset + length - GetContentOffset(), &lineLayout); + SetLength(offset + length - GetContentOffset(), &aLineLayout); // Ensure that the textrun will be rebuilt ClearTextRun(); } @@ -6341,7 +6362,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, } gfxSkipCharsIterator iter = - EnsureTextRun(ctx, lineContainer, lineLayout.GetLine(), &flowEndInTextRun); + EnsureTextRun(ctx, lineContainer, aLineLayout.GetLine(), &flowEndInTextRun); if (mTextRun && iter.GetOriginalEnd() < offset + length) { // The textrun does not map enough text for this frame. This can happen @@ -6350,13 +6371,13 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // consumed all the text of the textrun. We need a new textrun. ClearTextRun(); iter = EnsureTextRun(ctx, lineContainer, - lineLayout.GetLine(), &flowEndInTextRun); + aLineLayout.GetLine(), &flowEndInTextRun); } if (!mTextRun) { ClearMetrics(aMetrics); aStatus = NS_FRAME_COMPLETE; - return NS_OK; + return; } NS_ASSERTION(gfxSkipCharsIterator(iter).ConvertOriginalToSkipped(offset + length) @@ -6369,7 +6390,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, iter.SetOriginalOffset(offset); nscoord xOffsetForTabs = (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TAB) ? - (lineLayout.GetCurrentFrameXDistanceFromBlock() - + (aLineLayout.GetCurrentFrameXDistanceFromBlock() - lineContainer->GetUsedBorderAndPadding().left) : -1; PropertyProvider provider(mTextRun, textStyle, frag, this, iter, length, @@ -6388,7 +6409,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, #endif PRInt32 limitLength = length; - PRInt32 forceBreak = lineLayout.GetForcedBreakPosition(mContent); + PRInt32 forceBreak = aLineLayout.GetForcedBreakPosition(mContent); PRBool forceBreakAfter = PR_FALSE; if (forceBreak >= offset + length) { forceBreakAfter = forceBreak == offset + length; @@ -6418,16 +6439,16 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, PRUint32 transformedLastBreak = 0; PRBool usedHyphenation; gfxFloat trimmedWidth = 0; - gfxFloat availWidth = aReflowState.availableWidth; + gfxFloat availWidth = aAvailableWidth; PRBool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant(); PRInt32 unusedOffset; gfxBreakPriority breakPriority; - lineLayout.GetLastOptionalBreakPosition(&unusedOffset, &breakPriority); + aLineLayout.GetLastOptionalBreakPosition(&unusedOffset, &breakPriority); PRUint32 transformedCharsFit = mTextRun->BreakAndMeasureText(transformedOffset, transformedLength, (GetStateBits() & TEXT_START_OF_LINE) != 0, availWidth, - &provider, !lineLayout.LineIsBreakable(), + &provider, !aLineLayout.LineIsBreakable(), canTrimTrailingWhitespace ? &trimmedWidth : nsnull, &textMetrics, boundingBoxType, ctx, &usedHyphenation, &transformedLastBreak, @@ -6501,9 +6522,9 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, if (!brokeText && lastBreak >= 0) { // Since everything fit and no break was forced, // record the last break opportunity - NS_ASSERTION(textMetrics.mAdvanceWidth - trimmableWidth <= aReflowState.availableWidth, + NS_ASSERTION(textMetrics.mAdvanceWidth - trimmableWidth <= aAvailableWidth, "If the text doesn't fit, and we have a break opportunity, why didn't MeasureText use it?"); - lineLayout.NotifyOptionalBreakPosition(mContent, lastBreak, PR_TRUE, breakPriority); + aLineLayout.NotifyOptionalBreakPosition(mContent, lastBreak, PR_TRUE, breakPriority); } PRInt32 contentLength = offset + charsFit - GetContentOffset(); @@ -6553,7 +6574,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, aMetrics.mOverflowArea.UnionRect(boundingBox, nsRect(0, 0, aMetrics.width, aMetrics.height)); - UnionTextDecorationOverflow(aPresContext, provider, &aMetrics.mOverflowArea); + UnionTextDecorationOverflow(presContext, provider, &aMetrics.mOverflowArea); ///////////////////////////////////////////////////////////////////// // Clean up, update state @@ -6565,13 +6586,13 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // at most one space so there's no way for trimmable width from a previous // frame to accumulate with trimmable width from this frame.) if (transformedCharsFit > 0) { - lineLayout.SetTrimmableWidth(NSToCoordFloor(trimmableWidth)); + aLineLayout.SetTrimmableWidth(NSToCoordFloor(trimmableWidth)); AddStateBits(TEXT_HAS_NONCOLLAPSED_CHARACTERS); } if (charsFit > 0 && charsFit == length && HasSoftHyphenBefore(frag, mTextRun, offset, end)) { // Record a potential break after final soft hyphen - lineLayout.NotifyOptionalBreakPosition(mContent, offset + length, + aLineLayout.NotifyOptionalBreakPosition(mContent, offset + length, textMetrics.mAdvanceWidth + provider.GetHyphenWidth() <= availWidth, eNormalBreak); } @@ -6592,8 +6613,8 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, if (textMetrics.mAdvanceWidth - trimmableWidth > availWidth) { breakAfter = PR_TRUE; } else { - lineLayout.NotifyOptionalBreakPosition(mContent, offset + length, PR_TRUE, - eNormalBreak); + aLineLayout.NotifyOptionalBreakPosition(mContent, offset + length, + PR_TRUE, eNormalBreak); } } @@ -6607,12 +6628,12 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, } else if (contentLength > 0 && mContentOffset + contentLength - 1 == newLineOffset) { // Ends in \n aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus); - lineLayout.SetLineEndsInBR(PR_TRUE); + aLineLayout.SetLineEndsInBR(PR_TRUE); } else if (breakAfter) { aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus); } if (completedFirstLetter) { - lineLayout.SetFirstLetterStyleOK(PR_FALSE); + aLineLayout.SetFirstLetterStyleOK(PR_FALSE); aStatus |= NS_INLINE_BREAK_FIRST_LETTER_COMPLETE; } @@ -6648,11 +6669,11 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, NS_ASSERTION(numJustifiableCharacters <= charsFit, "Bad justifiable character count"); - lineLayout.SetTextJustificationWeights(numJustifiableCharacters, + aLineLayout.SetTextJustificationWeights(numJustifiableCharacters, charsFit - numJustifiableCharacters); } - SetLength(contentLength, &lineLayout); + SetLength(contentLength, &aLineLayout); if (mContent->HasFlag(NS_TEXT_IN_SELECTION)) { SelectionDetails* details = GetSelectionDetails(); @@ -6672,8 +6693,6 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, aMetrics.width, aMetrics.height, aMetrics.ascent, aStatus); #endif - NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); - return NS_OK; } /* virtual */ PRBool