Bug 1815140 Part 1: Make Grid dom object an idempotent property of its frame. r=emilio

This ensures that repeated calls to Element::GetGridFragments will return
an array of idempotent Grid objects for each fragment. This is
accomplished by making the Grid object hold a WeakFrame back to its
originating frame, and updating a property on construction and
destruction.

Differential Revision: https://phabricator.services.mozilla.com/D169724
This commit is contained in:
Brad Werth 2023-02-21 04:06:37 +00:00
parent f14e041e65
commit 79ab63aee9
5 changed files with 42 additions and 2 deletions

View File

@ -3563,7 +3563,16 @@ void Element::GetGridFragments(nsTArray<RefPtr<Grid>>& aResult) {
// If we get a nsGridContainerFrame from the prior call,
// all the next-in-flow frames will also be nsGridContainerFrames.
while (frame) {
aResult.AppendElement(new Grid(this, frame));
// Get the existing Grid object, if it exists. This object is
// guaranteed to be up-to-date because GetGridFrameWithComputedInfo
// will delete an existing one when regenerating grid info.
Grid* gridFragment = frame->GetGridFragmentInfo();
if (!gridFragment) {
// Grid constructor will add itself as a property to frame, and the
// destructor will remove itself if the frame still exists.
gridFragment = new Grid(this, frame);
}
aResult.AppendElement(gridFragment);
frame = static_cast<nsGridContainerFrame*>(frame->GetNextInFlow());
}
}

View File

@ -25,11 +25,14 @@ NS_INTERFACE_MAP_END
Grid::Grid(nsISupports* aParent, nsGridContainerFrame* aFrame)
: mParent(do_QueryInterface(aParent)),
mFrame(aFrame),
mRows(new GridDimension(this)),
mCols(new GridDimension(this)) {
MOZ_ASSERT(aFrame,
"Should never be instantiated with a null nsGridContainerFrame");
aFrame->SetProperty(nsGridContainerFrame::GridFragmentInfo(), this);
// Construct areas first, because lines may need to reference them
// to extract additional names for boundary lines.
@ -80,7 +83,14 @@ Grid::Grid(nsISupports* aParent, nsGridContainerFrame* aFrame)
mCols->SetLineInfo(columnTrackInfo, columnLineInfo, mAreas, false);
}
Grid::~Grid() = default;
Grid::~Grid() {
// If mFrame is still alive, clear the property that points back to us.
if (mFrame.IsAlive()) {
mFrame->RemoveProperty(nsGridContainerFrame::GridFragmentInfo());
}
// Our member variables are correctly handled by default destruction.
}
JSObject* Grid::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
return Grid_Binding::Wrap(aCx, this, aGivenProto);

View File

@ -38,6 +38,7 @@ class Grid : public nsISupports, public nsWrapperCache {
protected:
nsCOMPtr<Element> mParent;
WeakFrame mFrame;
RefPtr<GridDimension> mRows;
RefPtr<GridDimension> mCols;
nsTArray<RefPtr<GridArea>> mAreas;

View File

@ -8919,6 +8919,11 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
// since this bit is only set by accessing a ChromeOnly property, and
// therefore can't unduly slow down normal web browsing.
// Clear our GridFragmentInfo property, which might be holding a stale
// dom::Grid object built from previously-computed info. This will
// ensure that the next call to GetGridFragments will create a new one.
RemoveProperty(GridFragmentInfo());
// Now that we know column and row sizes and positions, set
// the ComputedGridTrackInfo and related properties

View File

@ -18,6 +18,9 @@
namespace mozilla {
class PresShell;
namespace dom {
class Grid;
}
} // namespace mozilla
/**
@ -214,6 +217,18 @@ class nsGridContainerFrame final : public nsContainerFrame,
return info;
}
/**
* This property is set by the creation of a dom::Grid object, and cleared by
* its destructor. Since the Grid object manages the lifecycle, the property
* itself is set without a destructor. The property is also cleared whenever
* new grid computed info is generated during reflow, ensuring that we aren't
* holding a stale dom::Grid object.
*/
NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(GridFragmentInfo, mozilla::dom::Grid)
mozilla::dom::Grid* GetGridFragmentInfo() {
return GetProperty(GridFragmentInfo());
}
struct AtomKey {
RefPtr<nsAtom> mKey;