Bug 580167 part 1. Create an nsTextFrame::ReflowText that doesn't need a reflow state. r=dbaron

This commit is contained in:
Boris Zbarsky 2010-08-25 14:54:46 -04:00
Родитель fecae963b6
Коммит 607cf078b1
2 изменённых файлов: 66 добавлений и 42 удалений

Просмотреть файл

@ -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();

Просмотреть файл

@ -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