Bug 1389743 - Only reconstruct frames synchronously from ContentRemoved when called from frame construction

Tag #1375
This commit is contained in:
Matt A. Tobin 2020-04-17 06:14:10 -04:00 committed by Roy Tam
commit f63cd76698
9 changed files with 201 additions and 285 deletions

View file

@ -97,8 +97,8 @@ private:
// aChild is the child being inserted for inserts, and the first
// child being appended for appends.
bool MaybeConstructLazily(Operation aOperation,
nsIContent* aContainer,
nsIContent* aChild);
nsIContent* aContainer,
nsIContent* aChild);
// Issues a single ContentInserted for each child of aContainer in the range
// [aStartChild, aEndChild).
@ -152,8 +152,8 @@ private:
// Returns true if parent was recreated due to frameset child, false otherwise.
bool MaybeRecreateForFrameset(nsIFrame* aParentFrame,
nsIContent* aStartChild,
nsIContent* aEndChild);
nsIContent* aStartChild,
nsIContent* aEndChild);
public:
/**
@ -225,6 +225,11 @@ public:
nsILayoutHistoryState* aFrameState,
bool aAllowLazyConstruction);
public:
// FIXME(emilio): How important is it to keep the frame tree state around for
// REMOVE_DESTROY_FRAMES?
//
// Seems like otherwise we could just remove it.
enum RemoveFlags {
REMOVE_CONTENT, REMOVE_FOR_RECONSTRUCTION, REMOVE_DESTROY_FRAMES };
/**
@ -243,12 +248,11 @@ public:
* only when aFlags == REMOVE_DESTROY_FRAMES, otherwise it will only be
* captured if we reconstructed frames for an ancestor.
*/
void ContentRemoved(nsIContent* aContainer,
nsIContent* aChild,
nsIContent* aOldNextSibling,
RemoveFlags aFlags,
bool* aDidReconstruct,
nsIContent** aDestroyedFramesFor = nullptr);
void ContentRemoved(nsIContent* aContainer,
nsIContent* aChild,
nsIContent* aOldNextSibling,
RemoveFlags aFlags,
bool* aDidReconstruct);
void CharacterDataChanged(nsIContent* aContent,
CharacterDataChangeInfo* aInfo);
@ -280,14 +284,10 @@ public:
/**
* Destroy the frames for aContent. Note that this may destroy frames
* for an ancestor instead - aDestroyedFramesFor contains the content node
* where frames were actually destroyed (which should be used in the
* ContentInserted call to recreate frames). The frame tree state
* is captured before the frames are destroyed and can be retrieved using
* GetLastCapturedLayoutHistoryState().
* for an ancestor instead - aDidReconstruct contains whether a reconstruct
* was posted for any ancestor.
*/
void DestroyFramesFor(nsIContent* aContent,
nsIContent** aDestroyedFramesFor);
void DestroyFramesFor(nsIContent* aContent, bool* aDidReconstruct);
// Request to create a continuing frame. This method never returns null.
nsIFrame* CreateContinuingFrame(nsPresContext* aPresContext,
@ -322,15 +322,6 @@ public:
nsContainerFrame* GetDocElementContainingBlock()
{ return mDocElementContainingBlock; }
/**
* Return the layout history state that was captured in the last
* ContentRemoved / RecreateFramesForContent call.
*/
nsILayoutHistoryState* GetLastCapturedLayoutHistoryState()
{
return mTempFrameTreeState;
}
private:
struct FrameConstructionItem;
class FrameConstructionItemList;
@ -1712,34 +1703,37 @@ private:
*/
nsStyleContext* MaybeRecreateFramesForElement(Element* aElement);
/**
* Whether insertion should be done synchronously or asynchronously.
*
* Generally, insertion is synchronous if we're reconstructing something from
* frame construction/reconstruction, and async if we're removing stuff, like
* from ContentRemoved.
*/
enum class InsertionKind
{
Sync,
Async,
};
/**
* Recreate frames for aContent.
* @param aContent the content to recreate frames for
* @param aAsyncInsert if true then a restyle event will be posted to handle
* the required ContentInserted call instead of doing it immediately.
* @param aFlags normally you want to pass REMOVE_FOR_RECONSTRUCTION here
* @param aDestroyedFramesFor if non-null, it will contain the content that
* was actually reframed - it may be different than aContent.
*/
void
RecreateFramesForContent(nsIContent* aContent,
bool aAsyncInsert,
RemoveFlags aFlags,
nsIContent** aDestroyedFramesFor);
void RecreateFramesForContent(nsIContent* aContent,
InsertionKind aInsertionKind,
RemoveFlags aFlags);
// If removal of aFrame from the frame tree requires reconstruction of some
// containing block (either of aFrame or of its parent) due to {ib} splits or
// table pseudo-frames, recreate the relevant frame subtree. The return value
// indicates whether this happened. If this method returns true, *aResult is
// the return value of ReframeContainingBlock or RecreateFramesForContent. If
// this method returns false, the value of *aResult is not affected. aFrame
// and aResult must not be null. aFrame must be the result of a
// indicates whether this happened. aFrame must be the result of a
// GetPrimaryFrame() call on a content node (which means its parent is also
// not null). If this method returns true, aDestroyedFramesFor contains the
// content that was reframed.
bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
RemoveFlags aFlags,
nsIContent** aDestroyedFramesFor);
// not null).
bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
InsertionKind aInsertionKind,
RemoveFlags aFlags);
nsIFrame* CreateContinuingOuterTableFrame(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
@ -1863,9 +1857,9 @@ private:
bool aIsAppend,
nsIFrame* aPrevSibling);
void ReframeContainingBlock(nsIFrame* aFrame,
RemoveFlags aFlags,
nsIContent** aReframeContent);
void ReframeContainingBlock(nsIFrame* aFrame,
InsertionKind aInsertionKind,
RemoveFlags aFlags);
//----------------------------------------