Bug 385607. Ensure that whitespace is collapsed across text-run boundaries across incremental updates like adding/removing frames in the middle of the textrun. r+sr+a=dbaron

This commit is contained in:
roc+@cs.cmu.edu 2007-09-17 20:00:16 -07:00
Родитель 662617a914
Коммит 9a93a48ef0
4 изменённых файлов: 47 добавлений и 6 удалений

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

@ -665,6 +665,7 @@ nsBlockFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
}
// XXX Bug NNNNNN Should probably handle percentage text-indent.
data.line = &line;
nsIFrame *kid = line->mFirstChild;
for (PRInt32 i = 0, i_end = line->GetChildCount(); i != i_end;
++i, kid = kid->GetNextSibling()) {
@ -736,6 +737,7 @@ nsBlockFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
}
// XXX Bug NNNNNN Should probably handle percentage text-indent.
data.line = &line;
nsIFrame *kid = line->mFirstChild;
for (PRInt32 i = 0, i_end = line->GetChildCount(); i != i_end;
++i, kid = kid->GetNextSibling()) {
@ -4798,12 +4800,19 @@ nsBlockFrame::AddFrames(nsIFrame* aFrameList,
prevSibLine->SetChildCount(prevSibLine->GetChildCount() - rem);
prevSibLine->MarkDirty();
}
// Force the lines next to where we're inserting content to regenerate
// their textruns
prevSibLine->SetInvalidateTextRuns(PR_TRUE);
if (prevSibLine.next() != end_lines()) {
prevSibLine.next()->SetInvalidateTextRuns(PR_TRUE);
}
// Now (partially) join the sibling lists together
aPrevSibling->SetNextSibling(aFrameList);
}
else if (! mLines.empty()) {
prevSiblingNextFrame = mLines.front()->mFirstChild;
mLines.front()->SetInvalidateTextRuns(PR_TRUE);
}
// Walk through the new frames being added and update the line data
@ -5212,6 +5221,10 @@ found_frame:;
NS_ERROR("can't find deleted frame in lines");
return NS_ERROR_FAILURE;
}
if (line != mLines.front()) {
line.prev()->SetInvalidateTextRuns(PR_TRUE);
}
if (prevSibling && !prevSibling->GetNextSibling()) {
// We must have found the first frame in the overflow line list. So
@ -5224,6 +5237,8 @@ found_frame:;
NS_ASSERTION(this == aDeletedFrame->GetParent(), "messed up delete code");
NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line");
line->SetInvalidateTextRuns(PR_TRUE);
// If the frame being deleted is the last one on the line then
// optimize away the line->Contains(next-in-flow) call below.
PRBool isLastFrameOnLine = (1 == line->GetChildCount() ||
@ -5370,6 +5385,10 @@ found_frame:;
}
}
}
if (line.next() != line_end) {
line.next()->SetInvalidateTextRuns(PR_TRUE);
}
#ifdef DEBUG
VerifyLines(PR_TRUE);
@ -6104,10 +6123,16 @@ nsBlockFrame::ChildIsDirty(nsIFrame* aChild)
// otherwise we have an empty line list, and ReflowDirtyLines
// will handle reflowing the bullet.
} else {
// Mark the line containing the child frame dirty.
// Mark the line containing the child frame dirty. We would rather do this
// in MarkIntrinsicWidthsDirty but that currently won't tell us which
// child is being dirtied.
line_iterator fline = FindLineFor(aChild);
if (fline != end_lines())
if (fline != end_lines()) {
// An inline descendant might have been added or removed, so we should
// reconstruct textruns.
fline->SetInvalidateTextRuns(PR_TRUE);
MarkLineDirty(fline);
}
}
nsBlockFrameSuper::ChildIsDirty(aChild);

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

@ -92,6 +92,7 @@ class nsDisplayListSet;
class nsDisplayList;
class gfxSkipChars;
class gfxSkipCharsIterator;
class nsLineList_iterator;
struct nsPeekOffsetStruct;
struct nsPoint;
@ -1137,12 +1138,16 @@ public:
*/
struct InlineIntrinsicWidthData {
InlineIntrinsicWidthData()
: prevLines(0)
: line(nsnull)
, prevLines(0)
, currentLine(0)
, skipWhitespace(PR_TRUE)
, trailingWhitespace(0)
{}
// The line. This may be null if the inlines are not associated with a block.
const nsLineList_iterator* line;
// The maximum intrinsic width for all previous lines.
nscoord prevLines;

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

@ -305,6 +305,15 @@ public:
return mFlags.mLineWrapped;
}
// mInvalidateTextRuns bit
void SetInvalidateTextRuns(PRBool aOn) {
NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!");
mFlags.mInvalidateTextRuns = aOn;
}
PRBool GetInvalidateTextRuns() const {
return mFlags.mInvalidateTextRuns;
}
// mResizeReflowOptimizationDisabled bit
void DisableResizeReflowOptimization() {
mFlags.mResizeReflowOptimizationDisabled = PR_TRUE;
@ -487,6 +496,7 @@ public:
PRUint32 mBlock : 1;
PRUint32 mImpactedByFloat : 1;
PRUint32 mLineWrapped: 1;
PRUint32 mInvalidateTextRuns : 1;
PRUint32 mResizeReflowOptimizationDisabled: 1; // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow
PRUint32 mEmptyCacheValid: 1;
PRUint32 mEmptyCacheState: 1;

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

@ -1206,6 +1206,7 @@ BuildTextRuns(nsIRenderingContext* aRC, nsTextFrame* aForFrame,
line = forwardIterator.GetLine();
if (line->IsBlock())
break;
line->SetInvalidateTextRuns(PR_FALSE);
scanner.SetAtStartOfLine();
scanner.SetCommonAncestorWithLastFrame(nsnull);
nsIFrame* child = line->mFirstChild;
@ -1966,7 +1967,7 @@ nsTextFrame::EnsureTextRun(nsIRenderingContext* aRC, nsIFrame* aLineContainer,
const nsLineList::iterator* aLine,
PRUint32* aFlowEndInTextRun)
{
if (mTextRun) {
if (mTextRun && (!aLine || !(*aLine)->GetInvalidateTextRuns())) {
if (mTextRun->GetExpirationState()->IsTracked()) {
gTextRuns->MarkUsed(mTextRun);
}
@ -5001,7 +5002,7 @@ nsTextFrame::AddInlineMinWidthForFlow(nsIRenderingContext *aRenderingContext,
{
PRUint32 flowEndInTextRun;
gfxSkipCharsIterator iter =
EnsureTextRun(aRenderingContext, nsnull, nsnull, &flowEndInTextRun);
EnsureTextRun(aRenderingContext, nsnull, aData->line, &flowEndInTextRun);
if (!mTextRun)
return;
@ -5099,7 +5100,7 @@ nsTextFrame::AddInlinePrefWidthForFlow(nsIRenderingContext *aRenderingContext,
{
PRUint32 flowEndInTextRun;
gfxSkipCharsIterator iter =
EnsureTextRun(aRenderingContext, nsnull, nsnull, &flowEndInTextRun);
EnsureTextRun(aRenderingContext, nsnull, aData->line, &flowEndInTextRun);
if (!mTextRun)
return;