From a017796f685881116bcd00b7ac6635c8843013be Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" Date: Thu, 24 Aug 2000 04:26:43 +0000 Subject: [PATCH] bug 45152 (Typed text does not render in TextAreas with a horizontal scrollbar) fixed by adding a flag in nsLineBox for the content of a line to mark it "forceInvalidate", logic in nsLineLayout to set the line dirty for initial reflow of text frames, and logic in block to check the new flag. r=kin --- layout/generic/nsBlockFrame.cpp | 15 ++++++- layout/generic/nsBlockFrame.h | 2 + layout/generic/nsBlockReflowState.cpp | 15 ++++++- layout/generic/nsBlockReflowState.h | 15 ++++++- layout/generic/nsLineBox.h | 14 ++++++- layout/generic/nsLineLayout.cpp | 43 +++++++++++++++++++++ layout/html/base/src/nsBlockFrame.cpp | 15 ++++++- layout/html/base/src/nsBlockFrame.h | 2 + layout/html/base/src/nsBlockReflowState.cpp | 15 ++++++- layout/html/base/src/nsBlockReflowState.h | 15 ++++++- layout/html/base/src/nsLineBox.h | 14 ++++++- layout/html/base/src/nsLineLayout.cpp | 43 +++++++++++++++++++++ 12 files changed, 198 insertions(+), 10 deletions(-) diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index d070de2d3d44..ec16151e5fef 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -2674,6 +2674,17 @@ nsBlockFrame::FindLineFor(nsIFrame* aFrame, return line; } +// SEC: added GetCurrentLine() for bug 45152 +// we need a way for line layout to know what line is being reflowed, +// but we don't want to expose the innards of nsBlockReflowState. +nsresult +nsBlockFrame::GetCurrentLine(nsBlockReflowState *aState, nsLineBox ** aOutCurrentLine) +{ + if (!aState || !aOutCurrentLine) return NS_ERROR_FAILURE; + *aOutCurrentLine = aState->mCurrentLine; + return NS_OK; +} + void nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsLineBox* aLine, @@ -3257,7 +3268,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // We don't really know what changed in the line, so use the union // of the old and new combined areas - if (aDamageDirtyArea) { + // SEC: added "aLine->IsForceInvalidate()" for bug 45152 + if (aDamageDirtyArea || aLine->IsForceInvalidate()) { + aLine->SetForceInvalidate(PR_FALSE); // doing the invalidate now, force flag to off nsRect combinedArea; aLine->GetCombinedArea(&combinedArea); diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index e2613af9b495..432d755e9c2d 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -161,6 +161,8 @@ public: nsLineBox* FindLineFor(nsIFrame* aFrame, nsLineBox** aPrevLineResult, PRBool* aIsFloaterResult); + static nsresult GetCurrentLine(nsBlockReflowState *aState, nsLineBox **aOutCurrentLine); + // return our ascent (i.e., ascent of our first line) // to support 'vertical-align: baseline' in table-cells nscoord GetAscent() const; diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index d070de2d3d44..ec16151e5fef 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -2674,6 +2674,17 @@ nsBlockFrame::FindLineFor(nsIFrame* aFrame, return line; } +// SEC: added GetCurrentLine() for bug 45152 +// we need a way for line layout to know what line is being reflowed, +// but we don't want to expose the innards of nsBlockReflowState. +nsresult +nsBlockFrame::GetCurrentLine(nsBlockReflowState *aState, nsLineBox ** aOutCurrentLine) +{ + if (!aState || !aOutCurrentLine) return NS_ERROR_FAILURE; + *aOutCurrentLine = aState->mCurrentLine; + return NS_OK; +} + void nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsLineBox* aLine, @@ -3257,7 +3268,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // We don't really know what changed in the line, so use the union // of the old and new combined areas - if (aDamageDirtyArea) { + // SEC: added "aLine->IsForceInvalidate()" for bug 45152 + if (aDamageDirtyArea || aLine->IsForceInvalidate()) { + aLine->SetForceInvalidate(PR_FALSE); // doing the invalidate now, force flag to off nsRect combinedArea; aLine->GetCombinedArea(&combinedArea); diff --git a/layout/generic/nsBlockReflowState.h b/layout/generic/nsBlockReflowState.h index d070de2d3d44..ec16151e5fef 100644 --- a/layout/generic/nsBlockReflowState.h +++ b/layout/generic/nsBlockReflowState.h @@ -2674,6 +2674,17 @@ nsBlockFrame::FindLineFor(nsIFrame* aFrame, return line; } +// SEC: added GetCurrentLine() for bug 45152 +// we need a way for line layout to know what line is being reflowed, +// but we don't want to expose the innards of nsBlockReflowState. +nsresult +nsBlockFrame::GetCurrentLine(nsBlockReflowState *aState, nsLineBox ** aOutCurrentLine) +{ + if (!aState || !aOutCurrentLine) return NS_ERROR_FAILURE; + *aOutCurrentLine = aState->mCurrentLine; + return NS_OK; +} + void nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsLineBox* aLine, @@ -3257,7 +3268,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // We don't really know what changed in the line, so use the union // of the old and new combined areas - if (aDamageDirtyArea) { + // SEC: added "aLine->IsForceInvalidate()" for bug 45152 + if (aDamageDirtyArea || aLine->IsForceInvalidate()) { + aLine->SetForceInvalidate(PR_FALSE); // doing the invalidate now, force flag to off nsRect combinedArea; aLine->GetCombinedArea(&combinedArea); diff --git a/layout/generic/nsLineBox.h b/layout/generic/nsLineBox.h index 8ef9094b586f..a89a45661083 100644 --- a/layout/generic/nsLineBox.h +++ b/layout/generic/nsLineBox.h @@ -136,7 +136,7 @@ protected: //---------------------------------------------------------------------- #define LINE_MAX_BREAK_TYPE ((1 << 4) - 1) -#define LINE_MAX_CHILD_COUNT ((1 << 24) - 1) +#define LINE_MAX_CHILD_COUNT ((1 << 21) - 1) #if NS_STYLE_CLEAR_LAST_VALUE > 15 need to rearrange the mBits bitfield; @@ -222,6 +222,15 @@ public: PRBool IsLineWrapped() const { return mFlags.mLineWrapped; } + + // mLineWrapped bit + void SetForceInvalidate(PRBool aOn) { + NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!"); + mFlags.mForceInvalidate = aOn; + } + PRBool IsForceInvalidate() const { + return mFlags.mForceInvalidate; + } // mChildCount value PRInt32 GetChildCount() const { @@ -328,10 +337,11 @@ public: PRUint32 mTrimmed : 1; PRUint32 mHasPercentageChild : 1; PRUint32 mLineWrapped: 1; + PRUint32 mForceInvalidate: 1; PRUint32 mBreakType : 4; - PRUint32 mChildCount : 22; + PRUint32 mChildCount : 21; }; struct ExtraData { diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index e8c72f5153fb..02e9740eba9a 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -25,6 +25,7 @@ */ #include "nsCOMPtr.h" #include "nsLineLayout.h" +#include "nsBlockFrame.h" #include "nsStyleConsts.h" #include "nsHTMLContainerFrame.h" #include "nsHTMLIIDs.h" @@ -934,6 +935,48 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, aFrame->Reflow(mPresContext, metrics, reflowState, aReflowStatus); + // SEC: added this next block for bug 45152 + // text frames don't know how to invalidate themselves on initial reflow. Do it for them here. + // This only shows up in textareas, so do a quick check to see if we're inside one + if (eReflowReason_Initial == reflowState.reason) + { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if (frameType && nsLayoutAtoms::textFrame == frameType.get()) + { // aFrame is a text frame, see if it's inside a text control + // although this is a bit slow, the frame tree shouldn't be too deep, it's only called + // for the text frame's initial reflow (once in the text frame's lifetime) + // and we don't make any expensive calls. + // Doing it this way shields us from knowing anything about the frame structure inside a text control. + nsIFrame *parentFrame; + aFrame->GetParent(&parentFrame); + PRBool inTextControl = PR_FALSE; + while (parentFrame) + { + nsCOMPtr frameType; + parentFrame->GetFrameType(getter_AddRefs(frameType)); + if (frameType) + { + if (nsLayoutAtoms::textInputFrame == frameType.get()) + { + inTextControl = PR_TRUE; // found it + break; + } + } + parentFrame->GetParent(&parentFrame); // advance the loop up the frame tree + } + if (inTextControl) + { + nsLineBox *currentLine=nsnull; + nsresult rv = nsBlockFrame::GetCurrentLine(mBlockRS, ¤tLine); + if (NS_SUCCEEDED(rv) && currentLine) { + currentLine->SetForceInvalidate(PR_TRUE); + } + } + } + } + // end fix for bug 45152 + pfd->mJustificationNumSpaces = mTextJustificationNumSpaces; pfd->mJustificationNumLetters = mTextJustificationNumLetters; diff --git a/layout/html/base/src/nsBlockFrame.cpp b/layout/html/base/src/nsBlockFrame.cpp index d070de2d3d44..ec16151e5fef 100644 --- a/layout/html/base/src/nsBlockFrame.cpp +++ b/layout/html/base/src/nsBlockFrame.cpp @@ -2674,6 +2674,17 @@ nsBlockFrame::FindLineFor(nsIFrame* aFrame, return line; } +// SEC: added GetCurrentLine() for bug 45152 +// we need a way for line layout to know what line is being reflowed, +// but we don't want to expose the innards of nsBlockReflowState. +nsresult +nsBlockFrame::GetCurrentLine(nsBlockReflowState *aState, nsLineBox ** aOutCurrentLine) +{ + if (!aState || !aOutCurrentLine) return NS_ERROR_FAILURE; + *aOutCurrentLine = aState->mCurrentLine; + return NS_OK; +} + void nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsLineBox* aLine, @@ -3257,7 +3268,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // We don't really know what changed in the line, so use the union // of the old and new combined areas - if (aDamageDirtyArea) { + // SEC: added "aLine->IsForceInvalidate()" for bug 45152 + if (aDamageDirtyArea || aLine->IsForceInvalidate()) { + aLine->SetForceInvalidate(PR_FALSE); // doing the invalidate now, force flag to off nsRect combinedArea; aLine->GetCombinedArea(&combinedArea); diff --git a/layout/html/base/src/nsBlockFrame.h b/layout/html/base/src/nsBlockFrame.h index e2613af9b495..432d755e9c2d 100644 --- a/layout/html/base/src/nsBlockFrame.h +++ b/layout/html/base/src/nsBlockFrame.h @@ -161,6 +161,8 @@ public: nsLineBox* FindLineFor(nsIFrame* aFrame, nsLineBox** aPrevLineResult, PRBool* aIsFloaterResult); + static nsresult GetCurrentLine(nsBlockReflowState *aState, nsLineBox **aOutCurrentLine); + // return our ascent (i.e., ascent of our first line) // to support 'vertical-align: baseline' in table-cells nscoord GetAscent() const; diff --git a/layout/html/base/src/nsBlockReflowState.cpp b/layout/html/base/src/nsBlockReflowState.cpp index d070de2d3d44..ec16151e5fef 100644 --- a/layout/html/base/src/nsBlockReflowState.cpp +++ b/layout/html/base/src/nsBlockReflowState.cpp @@ -2674,6 +2674,17 @@ nsBlockFrame::FindLineFor(nsIFrame* aFrame, return line; } +// SEC: added GetCurrentLine() for bug 45152 +// we need a way for line layout to know what line is being reflowed, +// but we don't want to expose the innards of nsBlockReflowState. +nsresult +nsBlockFrame::GetCurrentLine(nsBlockReflowState *aState, nsLineBox ** aOutCurrentLine) +{ + if (!aState || !aOutCurrentLine) return NS_ERROR_FAILURE; + *aOutCurrentLine = aState->mCurrentLine; + return NS_OK; +} + void nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsLineBox* aLine, @@ -3257,7 +3268,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // We don't really know what changed in the line, so use the union // of the old and new combined areas - if (aDamageDirtyArea) { + // SEC: added "aLine->IsForceInvalidate()" for bug 45152 + if (aDamageDirtyArea || aLine->IsForceInvalidate()) { + aLine->SetForceInvalidate(PR_FALSE); // doing the invalidate now, force flag to off nsRect combinedArea; aLine->GetCombinedArea(&combinedArea); diff --git a/layout/html/base/src/nsBlockReflowState.h b/layout/html/base/src/nsBlockReflowState.h index d070de2d3d44..ec16151e5fef 100644 --- a/layout/html/base/src/nsBlockReflowState.h +++ b/layout/html/base/src/nsBlockReflowState.h @@ -2674,6 +2674,17 @@ nsBlockFrame::FindLineFor(nsIFrame* aFrame, return line; } +// SEC: added GetCurrentLine() for bug 45152 +// we need a way for line layout to know what line is being reflowed, +// but we don't want to expose the innards of nsBlockReflowState. +nsresult +nsBlockFrame::GetCurrentLine(nsBlockReflowState *aState, nsLineBox ** aOutCurrentLine) +{ + if (!aState || !aOutCurrentLine) return NS_ERROR_FAILURE; + *aOutCurrentLine = aState->mCurrentLine; + return NS_OK; +} + void nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsLineBox* aLine, @@ -3257,7 +3268,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // We don't really know what changed in the line, so use the union // of the old and new combined areas - if (aDamageDirtyArea) { + // SEC: added "aLine->IsForceInvalidate()" for bug 45152 + if (aDamageDirtyArea || aLine->IsForceInvalidate()) { + aLine->SetForceInvalidate(PR_FALSE); // doing the invalidate now, force flag to off nsRect combinedArea; aLine->GetCombinedArea(&combinedArea); diff --git a/layout/html/base/src/nsLineBox.h b/layout/html/base/src/nsLineBox.h index 8ef9094b586f..a89a45661083 100644 --- a/layout/html/base/src/nsLineBox.h +++ b/layout/html/base/src/nsLineBox.h @@ -136,7 +136,7 @@ protected: //---------------------------------------------------------------------- #define LINE_MAX_BREAK_TYPE ((1 << 4) - 1) -#define LINE_MAX_CHILD_COUNT ((1 << 24) - 1) +#define LINE_MAX_CHILD_COUNT ((1 << 21) - 1) #if NS_STYLE_CLEAR_LAST_VALUE > 15 need to rearrange the mBits bitfield; @@ -222,6 +222,15 @@ public: PRBool IsLineWrapped() const { return mFlags.mLineWrapped; } + + // mLineWrapped bit + void SetForceInvalidate(PRBool aOn) { + NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!"); + mFlags.mForceInvalidate = aOn; + } + PRBool IsForceInvalidate() const { + return mFlags.mForceInvalidate; + } // mChildCount value PRInt32 GetChildCount() const { @@ -328,10 +337,11 @@ public: PRUint32 mTrimmed : 1; PRUint32 mHasPercentageChild : 1; PRUint32 mLineWrapped: 1; + PRUint32 mForceInvalidate: 1; PRUint32 mBreakType : 4; - PRUint32 mChildCount : 22; + PRUint32 mChildCount : 21; }; struct ExtraData { diff --git a/layout/html/base/src/nsLineLayout.cpp b/layout/html/base/src/nsLineLayout.cpp index e8c72f5153fb..02e9740eba9a 100644 --- a/layout/html/base/src/nsLineLayout.cpp +++ b/layout/html/base/src/nsLineLayout.cpp @@ -25,6 +25,7 @@ */ #include "nsCOMPtr.h" #include "nsLineLayout.h" +#include "nsBlockFrame.h" #include "nsStyleConsts.h" #include "nsHTMLContainerFrame.h" #include "nsHTMLIIDs.h" @@ -934,6 +935,48 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, aFrame->Reflow(mPresContext, metrics, reflowState, aReflowStatus); + // SEC: added this next block for bug 45152 + // text frames don't know how to invalidate themselves on initial reflow. Do it for them here. + // This only shows up in textareas, so do a quick check to see if we're inside one + if (eReflowReason_Initial == reflowState.reason) + { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if (frameType && nsLayoutAtoms::textFrame == frameType.get()) + { // aFrame is a text frame, see if it's inside a text control + // although this is a bit slow, the frame tree shouldn't be too deep, it's only called + // for the text frame's initial reflow (once in the text frame's lifetime) + // and we don't make any expensive calls. + // Doing it this way shields us from knowing anything about the frame structure inside a text control. + nsIFrame *parentFrame; + aFrame->GetParent(&parentFrame); + PRBool inTextControl = PR_FALSE; + while (parentFrame) + { + nsCOMPtr frameType; + parentFrame->GetFrameType(getter_AddRefs(frameType)); + if (frameType) + { + if (nsLayoutAtoms::textInputFrame == frameType.get()) + { + inTextControl = PR_TRUE; // found it + break; + } + } + parentFrame->GetParent(&parentFrame); // advance the loop up the frame tree + } + if (inTextControl) + { + nsLineBox *currentLine=nsnull; + nsresult rv = nsBlockFrame::GetCurrentLine(mBlockRS, ¤tLine); + if (NS_SUCCEEDED(rv) && currentLine) { + currentLine->SetForceInvalidate(PR_TRUE); + } + } + } + } + // end fix for bug 45152 + pfd->mJustificationNumSpaces = mTextJustificationNumSpaces; pfd->mJustificationNumLetters = mTextJustificationNumLetters;