зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
ec4aa569aa
Коммит
c2e407e442
|
@ -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() {}
|
||||
|
|
Загрузка…
Ссылка в новой задаче