Add ReLayout() - a driver that hides the details needed to re-sync a frame subtree in case of dynamic changes: rebuild of automatic data, re-resolve script styles, fire a reflow

This commit is contained in:
rbs%maths.uq.edu.au 2002-02-03 21:06:51 +00:00
Родитель ec4aa569aa
Коммит c2e407e442
2 изменённых файлов: 194 добавлений и 47 удалений

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

@ -41,7 +41,7 @@
#include "nsIDOMText.h"
#include "nsITextContent.h"
#include "nsIDOMMutationEvent.h"
#include "nsIFrameManager.h"
#include "nsStyleChangeList.h"
@ -897,40 +897,15 @@ nsMathMLContainerFrame::SetInitialChildList(nsIPresContext* aPresContext,
return TransmitAutomaticData(aPresContext);
}
// There are precise rules governing children of a MathML frame,
// and properties such as the scriptlevel depends on those rules.
// Hence for things to work, callers must use Append/Insert/etc wisely.
nsresult
nsMathMLContainerFrame::ChildListChanged(nsIPresContext* aPresContext,
nsIPresShell& aPresShell)
{
// wrap any new foreign child that may have crept in
WrapForeignFrames(aPresContext);
// re-sync our presentation data and embellishment data
#ifdef DEBUG_rbs
PRBool old = NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags);
#endif
RebuildAutomaticDataFor(aPresContext, this);
#ifdef DEBUG_rbs
PRBool now = NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags);
if (old != now)
NS_WARNING("REMIND: case where the embellished hierarchy has to be rebuilt too");
#endif
// grab the scriptlevel of our parent and re-resolve the style data in
// our subtree to sync any change of script sizes
nsPresentationData parentData;
GetPresentationDataFrom(mParent, parentData);
PropagateScriptStyleFor(aPresContext, this, parentData.scriptLevel);
// Ask our parent frame to reflow us
return ReflowDirtyChild(&aPresShell, nsnull);
}
// Note that this method re-builds the automatic data in the children -- not
// in aFrame itself (except for those particular operations that the frame
// may do in aFrame->TransmitAutomaticData()). The reason it works this way
// is because a container frame knows what it wants for its children, whereas
// children have no clue who their parent is. For example, it is <mfrac> who
// knows that its children have to be in scriptsizes, and has to transmit this
// information to them. Hence, when changes occur in a child frame, the child
// has to pass the re-build to its parent. Unfortunately, the extra cost for
// this is that it will re-sync in the siblings of the child as well.
/* static */ void
nsMathMLContainerFrame::RebuildAutomaticDataFor(nsIPresContext* aPresContext,
nsIFrame* aFrame)
@ -957,6 +932,77 @@ nsMathMLContainerFrame::RebuildAutomaticDataFor(nsIPresContext* aPresContext,
}
}
/* static */ nsresult
nsMathMLContainerFrame::ReLayout(nsIPresContext* aPresContext,
nsIFrame* aFrame)
{
// walk-up to the first frame that is a MathML frame, stop if we reach <math>
PRInt32 parentScriptLevel = 0;
nsIFrame* frame = aFrame;
while (frame) {
// stop if it is a MathML frame
nsIMathMLFrame* mathMLFrame;
frame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
if (mathMLFrame) {
nsIFrame* parent;
frame->GetParent(&parent);
nsPresentationData parentData;
GetPresentationDataFrom(parent, parentData);
parentScriptLevel = parentData.scriptLevel;
break;
}
// stop if we reach the root <math> tag
nsCOMPtr<nsIAtom> tag;
nsCOMPtr<nsIContent> content;
frame->GetContent(getter_AddRefs(content));
content->GetTag(*getter_AddRefs(tag));
if (tag.get() == nsMathMLAtoms::math) {
break;
}
// mark the frame dirty, and continue to climb up
nsFrameState state;
frame->GetFrameState(&state);
frame->SetFrameState(state | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
frame->GetParent(&frame);
}
// re-sync the presentation data and embellishment data of our children
#ifdef DEBUG_rbs
PRBool old = IsEmbellishOperator(frame);
#endif
RebuildAutomaticDataFor(aPresContext, frame);
#ifdef DEBUG_rbs
PRBool now = IsEmbellishOperator(frame);
if (old != now)
NS_WARNING("REMIND: case where the embellished hierarchy has to be rebuilt too");
#endif
// re-resolve the style data in our subtree to sync any change of script sizes
PropagateScriptStyleFor(aPresContext, frame, parentScriptLevel);
// Ask our parent frame to reflow us
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
return frame->ReflowDirtyChild(presShell, nsnull);
}
// There are precise rules governing children of a MathML frame,
// and properties such as the scriptlevel depends on those rules.
// Hence for things to work, callers must use Append/Insert/etc wisely.
nsresult
nsMathMLContainerFrame::ChildListChanged(nsIPresContext* aPresContext,
PRInt32 aModType)
{
if (aModType != nsIDOMMutationEvent::REMOVAL) {
// wrap any new foreign child that may have crept in
WrapForeignFrames(aPresContext);
}
return ReLayout(aPresContext, this);
}
NS_IMETHODIMP
nsMathMLContainerFrame::AppendFrames(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
@ -968,7 +1014,7 @@ nsMathMLContainerFrame::AppendFrames(nsIPresContext* aPresContext,
}
if (aFrameList) {
mFrames.AppendFrames(this, aFrameList);
return ChildListChanged(aPresContext, aPresShell);
return ChildListChanged(aPresContext, nsIDOMMutationEvent::ADDITION);
}
return NS_OK;
}
@ -986,7 +1032,7 @@ nsMathMLContainerFrame::InsertFrames(nsIPresContext* aPresContext,
if (aFrameList) {
// Insert frames after aPrevFrame
mFrames.InsertFrames(this, aPrevFrame, aFrameList);
return ChildListChanged(aPresContext, aPresShell);
return ChildListChanged(aPresContext, nsIDOMMutationEvent::ADDITION);
}
return NS_OK;
}
@ -1002,7 +1048,7 @@ nsMathMLContainerFrame::RemoveFrame(nsIPresContext* aPresContext,
}
// remove the child frame
mFrames.DestroyFrame(aPresContext, aOldFrame);
return ChildListChanged(aPresContext, aPresShell);
return ChildListChanged(aPresContext, nsIDOMMutationEvent::REMOVAL);
}
NS_IMETHODIMP
@ -1024,7 +1070,7 @@ nsMathMLContainerFrame::ReplaceFrame(nsIPresContext* aPresContext,
// XXX nobody seems to have been biten by the ambiguity yet
aOldFrame->Destroy(aPresContext);
return ChildListChanged(aPresContext, aPresShell);
return ChildListChanged(aPresContext, nsIDOMMutationEvent::MODIFICATION);
}
NS_IMETHODIMP

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

@ -167,6 +167,13 @@ public:
return nsHTMLContainerFrame::DidReflow(aPresContext, aReflowState, aStatus);
}
NS_IMETHOD
Paint(nsIPresContext* aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer,
PRUint32 aFlags = 0);
NS_IMETHOD
AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
@ -175,13 +182,6 @@ public:
PRInt32 aModType,
PRInt32 aHint);
NS_IMETHOD
Paint(nsIPresContext* aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer,
PRUint32 aFlags = 0);
// --------------------------------------------------------------------------
// Additional methods
@ -189,7 +189,7 @@ public:
// when changes (e.g., append/insert/remove) happen in our child list
virtual nsresult
ChildListChanged(nsIPresContext* aPresContext,
nsIPresShell& aPresShell);
PRInt32 aModType);
// helper to wrap non-MathML frames so that foreign elements (e.g., html:img)
// can mix better with other surrounding MathML markups
@ -306,6 +306,15 @@ public:
RebuildAutomaticDataFor(nsIPresContext* aPresContext,
nsIFrame* aFrame);
// helper to blow away the automatic data cached in a frame's subtree and
// re-layout its subtree to reflect changes that may have happen. In the
// event where aFrame isn't a MathML frame, it will first walk up to the
// ancestor that is a MathML frame, and re-layout from there -- this is to
// guarantee that automatic data will be rebuilt properly.
static nsresult
ReLayout(nsIPresContext* aPresContext,
nsIFrame* aFrame);
protected:
virtual PRIntn GetSkipSides() const { return 0; }
};
@ -336,6 +345,52 @@ public:
return rv;
}
NS_IMETHOD
AppendFrames(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aFrameList)
{
nsresult rv = nsBlockFrame::AppendFrames(aPresContext, aPresShell, aListName, aFrameList);
nsMathMLContainerFrame::ReLayout(aPresContext, this);
return rv;
}
NS_IMETHOD
InsertFrames(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList)
{
nsresult rv = nsBlockFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame, aFrameList);
nsMathMLContainerFrame::ReLayout(aPresContext, this);
return rv;
}
NS_IMETHOD
ReplaceFrame(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aOldFrame,
nsIFrame* aNewFrame)
{
nsresult rv = nsBlockFrame::ReplaceFrame(aPresContext, aPresShell, aListName, aOldFrame, aNewFrame);
nsMathMLContainerFrame::ReLayout(aPresContext, this);
return rv;
}
NS_IMETHOD
RemoveFrame(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aOldFrame)
{
nsresult rv = nsBlockFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame);
nsMathMLContainerFrame::ReLayout(aPresContext, this);
return rv;
}
protected:
nsMathMLmathBlockFrame() {}
virtual ~nsMathMLmathBlockFrame() {}
@ -358,6 +413,52 @@ public:
return rv;
}
NS_IMETHOD
AppendFrames(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aFrameList)
{
nsresult rv = nsInlineFrame::AppendFrames(aPresContext, aPresShell, aListName, aFrameList);
nsMathMLContainerFrame::ReLayout(aPresContext, this);
return rv;
}
NS_IMETHOD
InsertFrames(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList)
{
nsresult rv = nsInlineFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame, aFrameList);
nsMathMLContainerFrame::ReLayout(aPresContext, this);
return rv;
}
NS_IMETHOD
ReplaceFrame(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aOldFrame,
nsIFrame* aNewFrame)
{
nsresult rv = nsInlineFrame::ReplaceFrame(aPresContext, aPresShell, aListName, aOldFrame, aNewFrame);
nsMathMLContainerFrame::ReLayout(aPresContext, this);
return rv;
}
NS_IMETHOD
RemoveFrame(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aOldFrame)
{
nsresult rv = nsInlineFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame);
nsMathMLContainerFrame::ReLayout(aPresContext, this);
return rv;
}
protected:
nsMathMLmathInlineFrame() {}
virtual ~nsMathMLmathInlineFrame() {}