зеркало из https://github.com/mozilla/pjs.git
Bug 135146. Implement NS_FRAME_REFLOW_ROOT to allow reflows for <textarea> and <input type='text'> to be dispatched from the scroll frame within the nsGfxTextControlFrame2. r=kin, sr=attinasi
This commit is contained in:
Родитель
e87a5b9301
Коммит
b6fb7fe914
|
@ -209,6 +209,10 @@ typedef PRUint32 nsFrameState;
|
|||
// If this bit is set the frame has descendant with a view
|
||||
#define NS_FRAME_HAS_CHILD_WITH_VIEW 0x00040000
|
||||
|
||||
// If this bit is set, then reflow may be dispatched from the current
|
||||
// frame instead of the root frame.
|
||||
#define NS_FRAME_REFLOW_ROOT 0x00080000
|
||||
|
||||
// The lower 20 bits of the frame state word are reserved by this API.
|
||||
#define NS_FRAME_RESERVED 0x000FFFFF
|
||||
|
||||
|
|
|
@ -845,24 +845,21 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
|||
NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!state.GetFlag(BRS_ISINLINEINCRREFLOW)) {
|
||||
// XXXwaterson are we sure we don't need to do this work if BRS_ISINLINEINCRREFLOW?
|
||||
aStatus = state.mReflowStatus;
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
|
||||
if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) {
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUG_kipp
|
||||
ListTag(stdout); printf(": block is not complete\n");
|
||||
#endif
|
||||
}
|
||||
aStatus = state.mReflowStatus;
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
|
||||
if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) {
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUG_kipp
|
||||
ListTag(stdout); printf(": block is not complete\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// XXX_perf get rid of this! This is one of the things that makes
|
||||
// incremental reflow O(N^2).
|
||||
BuildFloaterList();
|
||||
}
|
||||
|
||||
// XXX_perf get rid of this! This is one of the things that makes
|
||||
// incremental reflow O(N^2).
|
||||
BuildFloaterList();
|
||||
|
||||
// Compute our final size
|
||||
ComputeFinalSize(aReflowState, state, aMetrics);
|
||||
|
@ -919,10 +916,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
|||
|
||||
// If this is an incremental reflow and we changed size, then make sure our
|
||||
// border is repainted if necessary
|
||||
//
|
||||
// XXXwaterson are we sure we can skip this if BRS_ISINLINEINCRREFLOW?
|
||||
if (!state.GetFlag(BRS_ISINLINEINCRREFLOW) &&
|
||||
(eReflowReason_Incremental == aReflowState.reason ||
|
||||
if ((eReflowReason_Incremental == aReflowState.reason ||
|
||||
eReflowReason_Dirty == aReflowState.reason)) {
|
||||
if (isStyleChange) {
|
||||
// This is only true if it's a style change reflow targeted at this
|
||||
|
@ -1005,10 +999,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
|||
// Let the absolutely positioned container reflow any absolutely positioned
|
||||
// child frames that need to be reflowed, e.g., elements with a percentage
|
||||
// based width/height
|
||||
//
|
||||
// XXXwaterson are we sure we can skip this if BRS_ISINLINEINCRREFLOW?
|
||||
if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames()
|
||||
&& !state.GetFlag(BRS_ISINLINEINCRREFLOW)) {
|
||||
if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames()) {
|
||||
nscoord containingBlockWidth;
|
||||
nscoord containingBlockHeight;
|
||||
nsRect childBounds;
|
||||
|
@ -1576,8 +1567,6 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState)
|
|||
}
|
||||
|
||||
if (line->IsInline()) {
|
||||
aState.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE);
|
||||
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
// We've been asked to compute the maximum width of the block
|
||||
// frame, which ReflowLine() will handle this by performing an
|
||||
|
@ -2131,9 +2120,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
aState.mReflowState.reflowCommand->GetType(type);
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
ListTag(stdout);
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s",
|
||||
kReflowCommandType[type], type,
|
||||
aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false");
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d)",
|
||||
kReflowCommandType[type], type);
|
||||
}
|
||||
else {
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
|
|
|
@ -176,8 +176,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
|
||||
aReflowState.rendContext,
|
||||
aReflowState.frame);
|
||||
|
||||
SetFlag(BRS_DAMAGECONSTRAINED, IsIncrementalDamageConstrained(aFrame));
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -190,32 +188,6 @@ nsBlockReflowState::~nsBlockReflowState()
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockReflowState::IsIncrementalDamageConstrained(nsIFrame* aBlockFrame) const
|
||||
{
|
||||
// see if the reflow will go through a text control. if so, we can optimize
|
||||
// because we know the text control won't change size.
|
||||
if ((eReflowReason_Incremental == mReflowState.reason) && (mReflowState.reflowCommand)) {
|
||||
nsIFrame* target;
|
||||
mReflowState.reflowCommand->GetTarget(target);
|
||||
while (target) {
|
||||
// starting with the target's parent, scan for a text control
|
||||
nsIFrame* parent;
|
||||
target->GetParent(&parent);
|
||||
if ((aBlockFrame == parent) || !parent) // the null check is paranoia, it should never happen
|
||||
break; // we found the block, so we know there's no text control between the block and target
|
||||
nsCOMPtr<nsIAtom> frameType;
|
||||
parent->GetFrameType(getter_AddRefs(frameType));
|
||||
if (frameType) {
|
||||
if (nsLayoutAtoms::textInputFrame == frameType.get())
|
||||
return PR_TRUE; // damage is constrained to the text control innards
|
||||
}
|
||||
target = parent; // advance the loop up the frame tree
|
||||
}
|
||||
}
|
||||
return PR_FALSE; // default case, damage is not constrained (or unknown)
|
||||
}
|
||||
|
||||
nsLineBox*
|
||||
nsBlockReflowState::NewLineBox(nsIFrame* aFrame,
|
||||
PRInt32 aCount,
|
||||
|
|
|
@ -112,10 +112,6 @@ public:
|
|||
protected:
|
||||
void RecoverFloaters(nsLineList::iterator aLine, nscoord aDeltaY);
|
||||
|
||||
// return PR_TRUE if the incremental reflow is 100% contained
|
||||
// within the bounds of an ancestor frame, relative to aBlockFrame
|
||||
PRBool IsIncrementalDamageConstrained(nsIFrame* aBlockFrame) const;
|
||||
|
||||
public:
|
||||
void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaY);
|
||||
|
||||
|
@ -248,14 +244,13 @@ public:
|
|||
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
||||
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
||||
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
||||
#define BRS_ISINLINEINCRREFLOW 0x00000010
|
||||
#define BRS_NOWRAP 0x00000020
|
||||
#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000080
|
||||
#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000400
|
||||
#define BRS_DAMAGECONSTRAINED 0x00000800 // is the target of an incremental reflow command inside a text control
|
||||
#define BRS_NOWRAP 0x00000010
|
||||
#define BRS_ISTOPMARGINROOT 0x00000020 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000040
|
||||
#define BRS_APPLYTOPMARGIN 0x00000080 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000100
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000200
|
||||
#define BRS_DAMAGECONSTRAINED 0x00000400 // is the target of an incremental reflow command inside a text control
|
||||
#define BRS_LASTFLAG BRS_DAMAGECONSTRAINED
|
||||
|
||||
PRInt16 mFlags;
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "nsHTMLIIDs.h"
|
||||
#include "nsFrame.h"
|
||||
#include "nsContainerFrame.h"
|
||||
|
||||
#include "nsLayoutAtoms.h"
|
||||
|
||||
nsresult
|
||||
NS_NewHTMLReflowCommand(nsHTMLReflowCommand** aInstancePtrResult,
|
||||
|
@ -144,13 +144,6 @@ nsHTMLReflowCommand::~nsHTMLReflowCommand()
|
|||
NS_IF_RELEASE(mListName);
|
||||
}
|
||||
|
||||
nsIFrame* nsHTMLReflowCommand::GetContainingBlock(nsIFrame* aFloater) const
|
||||
{
|
||||
nsIFrame* containingBlock;
|
||||
aFloater->GetParent(&containingBlock);
|
||||
return containingBlock;
|
||||
}
|
||||
|
||||
void nsHTMLReflowCommand::BuildPath()
|
||||
{
|
||||
#ifdef DEBUG_jesup
|
||||
|
@ -164,22 +157,15 @@ void nsHTMLReflowCommand::BuildPath()
|
|||
|
||||
mPath.Clear();
|
||||
|
||||
// Floating frames are handled differently. The path goes from the target
|
||||
// frame to the containing block, and then up the hierarchy
|
||||
const nsStyleDisplay* display;
|
||||
mTargetFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display);
|
||||
if (NS_STYLE_FLOAT_NONE != display->mFloats) {
|
||||
mPath.AppendElement((void*)mTargetFrame);
|
||||
|
||||
for (nsIFrame* f = GetContainingBlock(mTargetFrame); nsnull != f; f->GetParent(&f)) {
|
||||
mPath.AppendElement((void*)f);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (nsIFrame* f = mTargetFrame; nsnull != f; f->GetParent(&f)) {
|
||||
mPath.AppendElement((void*)f);
|
||||
}
|
||||
}
|
||||
// Construct the reflow path by walking up the through the frames'
|
||||
// parent chain until we reach either a `reflow root' or the root
|
||||
// frame in the frame hierarchy.
|
||||
nsIFrame *f = mTargetFrame;
|
||||
nsFrameState state;
|
||||
do {
|
||||
mPath.AppendElement(f);
|
||||
f->GetFrameState(&state);
|
||||
} while (!(state & NS_FRAME_REFLOW_ROOT) && (f->GetParent(&f), f != nsnull));
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -188,41 +174,61 @@ nsHTMLReflowCommand::Dispatch(nsIPresContext* aPresContext,
|
|||
const nsSize& aMaxSize,
|
||||
nsIRenderingContext& aRendContext)
|
||||
{
|
||||
// Build the path from the target frame (index 0) to the root frame
|
||||
// Build the path from the target frame (index 0)
|
||||
BuildPath();
|
||||
|
||||
// Send an incremental reflow notification to the root frame
|
||||
nsIFrame* root = (nsIFrame*)mPath[mPath.Count() - 1];
|
||||
// Send an incremental reflow notification to the first frame in the
|
||||
// path.
|
||||
nsIFrame* first = (nsIFrame*)mPath[mPath.Count() - 1];
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
aPresContext->GetShell(getter_AddRefs(shell));
|
||||
if (shell) {
|
||||
nsIFrame* rootFrame;
|
||||
shell->GetRootFrame(&rootFrame);
|
||||
NS_ASSERTION(rootFrame == root, "bad root frame");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nsnull != root) {
|
||||
mPath.RemoveElementAt(mPath.Count() - 1);
|
||||
nsIFrame* root;
|
||||
shell->GetRootFrame(&root);
|
||||
|
||||
nsHTMLReflowState reflowState(aPresContext, root, *this,
|
||||
&aRendContext, aMaxSize);
|
||||
nsReflowStatus status;
|
||||
// Remove the first frame from the path and reflow it.
|
||||
mPath.RemoveElementAt(mPath.Count() - 1);
|
||||
|
||||
root->WillReflow(aPresContext);
|
||||
nsContainerFrame::PositionFrameView(aPresContext, root);
|
||||
root->Reflow(aPresContext, aDesiredSize, reflowState, status);
|
||||
root->SizeTo(aPresContext, aDesiredSize.width, aDesiredSize.height);
|
||||
nsIView* view;
|
||||
root->GetView(aPresContext, &view);
|
||||
if (view) {
|
||||
nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, root, view,
|
||||
nsnull);
|
||||
}
|
||||
root->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
|
||||
}
|
||||
first->WillReflow(aPresContext);
|
||||
nsContainerFrame::PositionFrameView(aPresContext, first);
|
||||
|
||||
// If the first frame in the path is the root of the frame
|
||||
// hierarchy, then use all the available space. If it's simply a
|
||||
// `reflow root', then use the first frame's size as the available
|
||||
// space.
|
||||
//
|
||||
// XXXwaterson Beware that this is not sufficiently general to allow
|
||||
// arbitrary frames to be reflow roots. For example, and inline
|
||||
// frame cannot be a reflow root because nsHTMLReflowState::Init()
|
||||
// will try to walk up through the reflow state chain to find the
|
||||
// containing block.
|
||||
nsSize size;
|
||||
if (first == root)
|
||||
size = aMaxSize;
|
||||
else
|
||||
first->GetSize(size);
|
||||
|
||||
nsHTMLReflowState reflowState(aPresContext, first, *this,
|
||||
&aRendContext, size);
|
||||
|
||||
nsReflowStatus status;
|
||||
first->Reflow(aPresContext, aDesiredSize, reflowState, status);
|
||||
|
||||
// If an incremental reflow is initiated at a frame other than the
|
||||
// root frame, then its desired size had better not change!
|
||||
NS_ASSERTION(first == root ||
|
||||
(aDesiredSize.width == size.width && aDesiredSize.height == size.height),
|
||||
"non-root frame's desired size changed during an incremental reflow");
|
||||
|
||||
first->SizeTo(aPresContext, aDesiredSize.width, aDesiredSize.height);
|
||||
|
||||
nsIView* view;
|
||||
first->GetView(aPresContext, &view);
|
||||
if (view)
|
||||
nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, first, view, nsnull);
|
||||
|
||||
first->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -344,17 +350,8 @@ nsHTMLReflowCommand::List(FILE* out) const
|
|||
// Show the path, but without using mPath which is in an undefined
|
||||
// state at this point.
|
||||
if (mTargetFrame) {
|
||||
// Floating frames are handled differently. The path goes from the target
|
||||
// frame to the containing block, and then up the hierarchy
|
||||
PRBool didOne = PR_FALSE;
|
||||
nsIFrame* start = mTargetFrame;
|
||||
const nsStyleDisplay* display;
|
||||
mTargetFrame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
if (NS_STYLE_FLOAT_NONE != display->mFloats) {
|
||||
start = GetContainingBlock(mTargetFrame);
|
||||
}
|
||||
for (nsIFrame* f = start; nsnull != f; f->GetParent(&f)) {
|
||||
for (nsIFrame* f = mTargetFrame; nsnull != f; f->GetParent(&f)) {
|
||||
if (f != mTargetFrame) {
|
||||
fprintf(out, " ");
|
||||
nsFrame::ListTag(out, f);
|
||||
|
|
|
@ -175,7 +175,6 @@ public:
|
|||
|
||||
protected:
|
||||
void BuildPath();
|
||||
nsIFrame* GetContainingBlock(nsIFrame* aFloater) const;
|
||||
|
||||
private:
|
||||
nsReflowType mType;
|
||||
|
|
|
@ -209,6 +209,10 @@ typedef PRUint32 nsFrameState;
|
|||
// If this bit is set the frame has descendant with a view
|
||||
#define NS_FRAME_HAS_CHILD_WITH_VIEW 0x00040000
|
||||
|
||||
// If this bit is set, then reflow may be dispatched from the current
|
||||
// frame instead of the root frame.
|
||||
#define NS_FRAME_REFLOW_ROOT 0x00080000
|
||||
|
||||
// The lower 20 bits of the frame state word are reserved by this API.
|
||||
#define NS_FRAME_RESERVED 0x000FFFFF
|
||||
|
||||
|
|
|
@ -845,24 +845,21 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
|||
NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!state.GetFlag(BRS_ISINLINEINCRREFLOW)) {
|
||||
// XXXwaterson are we sure we don't need to do this work if BRS_ISINLINEINCRREFLOW?
|
||||
aStatus = state.mReflowStatus;
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
|
||||
if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) {
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUG_kipp
|
||||
ListTag(stdout); printf(": block is not complete\n");
|
||||
#endif
|
||||
}
|
||||
aStatus = state.mReflowStatus;
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
|
||||
if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) {
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUG_kipp
|
||||
ListTag(stdout); printf(": block is not complete\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// XXX_perf get rid of this! This is one of the things that makes
|
||||
// incremental reflow O(N^2).
|
||||
BuildFloaterList();
|
||||
}
|
||||
|
||||
// XXX_perf get rid of this! This is one of the things that makes
|
||||
// incremental reflow O(N^2).
|
||||
BuildFloaterList();
|
||||
|
||||
// Compute our final size
|
||||
ComputeFinalSize(aReflowState, state, aMetrics);
|
||||
|
@ -919,10 +916,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
|||
|
||||
// If this is an incremental reflow and we changed size, then make sure our
|
||||
// border is repainted if necessary
|
||||
//
|
||||
// XXXwaterson are we sure we can skip this if BRS_ISINLINEINCRREFLOW?
|
||||
if (!state.GetFlag(BRS_ISINLINEINCRREFLOW) &&
|
||||
(eReflowReason_Incremental == aReflowState.reason ||
|
||||
if ((eReflowReason_Incremental == aReflowState.reason ||
|
||||
eReflowReason_Dirty == aReflowState.reason)) {
|
||||
if (isStyleChange) {
|
||||
// This is only true if it's a style change reflow targeted at this
|
||||
|
@ -1005,10 +999,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
|||
// Let the absolutely positioned container reflow any absolutely positioned
|
||||
// child frames that need to be reflowed, e.g., elements with a percentage
|
||||
// based width/height
|
||||
//
|
||||
// XXXwaterson are we sure we can skip this if BRS_ISINLINEINCRREFLOW?
|
||||
if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames()
|
||||
&& !state.GetFlag(BRS_ISINLINEINCRREFLOW)) {
|
||||
if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames()) {
|
||||
nscoord containingBlockWidth;
|
||||
nscoord containingBlockHeight;
|
||||
nsRect childBounds;
|
||||
|
@ -1576,8 +1567,6 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState)
|
|||
}
|
||||
|
||||
if (line->IsInline()) {
|
||||
aState.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE);
|
||||
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
// We've been asked to compute the maximum width of the block
|
||||
// frame, which ReflowLine() will handle this by performing an
|
||||
|
@ -2131,9 +2120,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
aState.mReflowState.reflowCommand->GetType(type);
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
ListTag(stdout);
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s",
|
||||
kReflowCommandType[type], type,
|
||||
aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false");
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d)",
|
||||
kReflowCommandType[type], type);
|
||||
}
|
||||
else {
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
|
|
|
@ -176,8 +176,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
|
||||
aReflowState.rendContext,
|
||||
aReflowState.frame);
|
||||
|
||||
SetFlag(BRS_DAMAGECONSTRAINED, IsIncrementalDamageConstrained(aFrame));
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -190,32 +188,6 @@ nsBlockReflowState::~nsBlockReflowState()
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockReflowState::IsIncrementalDamageConstrained(nsIFrame* aBlockFrame) const
|
||||
{
|
||||
// see if the reflow will go through a text control. if so, we can optimize
|
||||
// because we know the text control won't change size.
|
||||
if ((eReflowReason_Incremental == mReflowState.reason) && (mReflowState.reflowCommand)) {
|
||||
nsIFrame* target;
|
||||
mReflowState.reflowCommand->GetTarget(target);
|
||||
while (target) {
|
||||
// starting with the target's parent, scan for a text control
|
||||
nsIFrame* parent;
|
||||
target->GetParent(&parent);
|
||||
if ((aBlockFrame == parent) || !parent) // the null check is paranoia, it should never happen
|
||||
break; // we found the block, so we know there's no text control between the block and target
|
||||
nsCOMPtr<nsIAtom> frameType;
|
||||
parent->GetFrameType(getter_AddRefs(frameType));
|
||||
if (frameType) {
|
||||
if (nsLayoutAtoms::textInputFrame == frameType.get())
|
||||
return PR_TRUE; // damage is constrained to the text control innards
|
||||
}
|
||||
target = parent; // advance the loop up the frame tree
|
||||
}
|
||||
}
|
||||
return PR_FALSE; // default case, damage is not constrained (or unknown)
|
||||
}
|
||||
|
||||
nsLineBox*
|
||||
nsBlockReflowState::NewLineBox(nsIFrame* aFrame,
|
||||
PRInt32 aCount,
|
||||
|
|
|
@ -112,10 +112,6 @@ public:
|
|||
protected:
|
||||
void RecoverFloaters(nsLineList::iterator aLine, nscoord aDeltaY);
|
||||
|
||||
// return PR_TRUE if the incremental reflow is 100% contained
|
||||
// within the bounds of an ancestor frame, relative to aBlockFrame
|
||||
PRBool IsIncrementalDamageConstrained(nsIFrame* aBlockFrame) const;
|
||||
|
||||
public:
|
||||
void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaY);
|
||||
|
||||
|
@ -248,14 +244,13 @@ public:
|
|||
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
||||
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
||||
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
||||
#define BRS_ISINLINEINCRREFLOW 0x00000010
|
||||
#define BRS_NOWRAP 0x00000020
|
||||
#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000080
|
||||
#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000400
|
||||
#define BRS_DAMAGECONSTRAINED 0x00000800 // is the target of an incremental reflow command inside a text control
|
||||
#define BRS_NOWRAP 0x00000010
|
||||
#define BRS_ISTOPMARGINROOT 0x00000020 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000040
|
||||
#define BRS_APPLYTOPMARGIN 0x00000080 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000100
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000200
|
||||
#define BRS_DAMAGECONSTRAINED 0x00000400 // is the target of an incremental reflow command inside a text control
|
||||
#define BRS_LASTFLAG BRS_DAMAGECONSTRAINED
|
||||
|
||||
PRInt16 mFlags;
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "nsHTMLIIDs.h"
|
||||
#include "nsFrame.h"
|
||||
#include "nsContainerFrame.h"
|
||||
|
||||
#include "nsLayoutAtoms.h"
|
||||
|
||||
nsresult
|
||||
NS_NewHTMLReflowCommand(nsHTMLReflowCommand** aInstancePtrResult,
|
||||
|
@ -144,13 +144,6 @@ nsHTMLReflowCommand::~nsHTMLReflowCommand()
|
|||
NS_IF_RELEASE(mListName);
|
||||
}
|
||||
|
||||
nsIFrame* nsHTMLReflowCommand::GetContainingBlock(nsIFrame* aFloater) const
|
||||
{
|
||||
nsIFrame* containingBlock;
|
||||
aFloater->GetParent(&containingBlock);
|
||||
return containingBlock;
|
||||
}
|
||||
|
||||
void nsHTMLReflowCommand::BuildPath()
|
||||
{
|
||||
#ifdef DEBUG_jesup
|
||||
|
@ -164,22 +157,15 @@ void nsHTMLReflowCommand::BuildPath()
|
|||
|
||||
mPath.Clear();
|
||||
|
||||
// Floating frames are handled differently. The path goes from the target
|
||||
// frame to the containing block, and then up the hierarchy
|
||||
const nsStyleDisplay* display;
|
||||
mTargetFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display);
|
||||
if (NS_STYLE_FLOAT_NONE != display->mFloats) {
|
||||
mPath.AppendElement((void*)mTargetFrame);
|
||||
|
||||
for (nsIFrame* f = GetContainingBlock(mTargetFrame); nsnull != f; f->GetParent(&f)) {
|
||||
mPath.AppendElement((void*)f);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (nsIFrame* f = mTargetFrame; nsnull != f; f->GetParent(&f)) {
|
||||
mPath.AppendElement((void*)f);
|
||||
}
|
||||
}
|
||||
// Construct the reflow path by walking up the through the frames'
|
||||
// parent chain until we reach either a `reflow root' or the root
|
||||
// frame in the frame hierarchy.
|
||||
nsIFrame *f = mTargetFrame;
|
||||
nsFrameState state;
|
||||
do {
|
||||
mPath.AppendElement(f);
|
||||
f->GetFrameState(&state);
|
||||
} while (!(state & NS_FRAME_REFLOW_ROOT) && (f->GetParent(&f), f != nsnull));
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -188,41 +174,61 @@ nsHTMLReflowCommand::Dispatch(nsIPresContext* aPresContext,
|
|||
const nsSize& aMaxSize,
|
||||
nsIRenderingContext& aRendContext)
|
||||
{
|
||||
// Build the path from the target frame (index 0) to the root frame
|
||||
// Build the path from the target frame (index 0)
|
||||
BuildPath();
|
||||
|
||||
// Send an incremental reflow notification to the root frame
|
||||
nsIFrame* root = (nsIFrame*)mPath[mPath.Count() - 1];
|
||||
// Send an incremental reflow notification to the first frame in the
|
||||
// path.
|
||||
nsIFrame* first = (nsIFrame*)mPath[mPath.Count() - 1];
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
aPresContext->GetShell(getter_AddRefs(shell));
|
||||
if (shell) {
|
||||
nsIFrame* rootFrame;
|
||||
shell->GetRootFrame(&rootFrame);
|
||||
NS_ASSERTION(rootFrame == root, "bad root frame");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nsnull != root) {
|
||||
mPath.RemoveElementAt(mPath.Count() - 1);
|
||||
nsIFrame* root;
|
||||
shell->GetRootFrame(&root);
|
||||
|
||||
nsHTMLReflowState reflowState(aPresContext, root, *this,
|
||||
&aRendContext, aMaxSize);
|
||||
nsReflowStatus status;
|
||||
// Remove the first frame from the path and reflow it.
|
||||
mPath.RemoveElementAt(mPath.Count() - 1);
|
||||
|
||||
root->WillReflow(aPresContext);
|
||||
nsContainerFrame::PositionFrameView(aPresContext, root);
|
||||
root->Reflow(aPresContext, aDesiredSize, reflowState, status);
|
||||
root->SizeTo(aPresContext, aDesiredSize.width, aDesiredSize.height);
|
||||
nsIView* view;
|
||||
root->GetView(aPresContext, &view);
|
||||
if (view) {
|
||||
nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, root, view,
|
||||
nsnull);
|
||||
}
|
||||
root->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
|
||||
}
|
||||
first->WillReflow(aPresContext);
|
||||
nsContainerFrame::PositionFrameView(aPresContext, first);
|
||||
|
||||
// If the first frame in the path is the root of the frame
|
||||
// hierarchy, then use all the available space. If it's simply a
|
||||
// `reflow root', then use the first frame's size as the available
|
||||
// space.
|
||||
//
|
||||
// XXXwaterson Beware that this is not sufficiently general to allow
|
||||
// arbitrary frames to be reflow roots. For example, and inline
|
||||
// frame cannot be a reflow root because nsHTMLReflowState::Init()
|
||||
// will try to walk up through the reflow state chain to find the
|
||||
// containing block.
|
||||
nsSize size;
|
||||
if (first == root)
|
||||
size = aMaxSize;
|
||||
else
|
||||
first->GetSize(size);
|
||||
|
||||
nsHTMLReflowState reflowState(aPresContext, first, *this,
|
||||
&aRendContext, size);
|
||||
|
||||
nsReflowStatus status;
|
||||
first->Reflow(aPresContext, aDesiredSize, reflowState, status);
|
||||
|
||||
// If an incremental reflow is initiated at a frame other than the
|
||||
// root frame, then its desired size had better not change!
|
||||
NS_ASSERTION(first == root ||
|
||||
(aDesiredSize.width == size.width && aDesiredSize.height == size.height),
|
||||
"non-root frame's desired size changed during an incremental reflow");
|
||||
|
||||
first->SizeTo(aPresContext, aDesiredSize.width, aDesiredSize.height);
|
||||
|
||||
nsIView* view;
|
||||
first->GetView(aPresContext, &view);
|
||||
if (view)
|
||||
nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, first, view, nsnull);
|
||||
|
||||
first->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -344,17 +350,8 @@ nsHTMLReflowCommand::List(FILE* out) const
|
|||
// Show the path, but without using mPath which is in an undefined
|
||||
// state at this point.
|
||||
if (mTargetFrame) {
|
||||
// Floating frames are handled differently. The path goes from the target
|
||||
// frame to the containing block, and then up the hierarchy
|
||||
PRBool didOne = PR_FALSE;
|
||||
nsIFrame* start = mTargetFrame;
|
||||
const nsStyleDisplay* display;
|
||||
mTargetFrame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
if (NS_STYLE_FLOAT_NONE != display->mFloats) {
|
||||
start = GetContainingBlock(mTargetFrame);
|
||||
}
|
||||
for (nsIFrame* f = start; nsnull != f; f->GetParent(&f)) {
|
||||
for (nsIFrame* f = mTargetFrame; nsnull != f; f->GetParent(&f)) {
|
||||
if (f != mTargetFrame) {
|
||||
fprintf(out, " ");
|
||||
nsFrame::ListTag(out, f);
|
||||
|
|
|
@ -175,7 +175,6 @@ public:
|
|||
|
||||
protected:
|
||||
void BuildPath();
|
||||
nsIFrame* GetContainingBlock(nsIFrame* aFloater) const;
|
||||
|
||||
private:
|
||||
nsReflowType mType;
|
||||
|
|
|
@ -3342,6 +3342,14 @@ nsGfxTextControlFrame2::SetInitialChildList(nsIPresContext* aPresContext,
|
|||
nsIFrame *first;
|
||||
FirstChild(aPresContext,nsnull, &first);
|
||||
|
||||
// Mark the scroll frame as being a reflow root. This will allow
|
||||
// incremental reflows to be initiated at the scroll frame, rather
|
||||
// than descending from the root frame of the frame hierarchy.
|
||||
nsFrameState state;
|
||||
first->GetFrameState(&state);
|
||||
state |= NS_FRAME_REFLOW_ROOT;
|
||||
first->SetFrameState(state);
|
||||
|
||||
//we must turn off scrollbars for singleline text controls
|
||||
PRInt32 type;
|
||||
GetType(&type);
|
||||
|
|
Загрузка…
Ссылка в новой задаче