gecko-dev/layout/base/DepthOrderedFrameList.h
Emilio Cobos Álvarez e25472e749 Bug 1908242 - Make sure that sticky items are processed in the right order. r=TYLin
We rely on positioning ancestors before descendants to get the right
position. This was very implicitly enforced before the regressing bug,
by reframing on position changes (due to the order
StickyScrollContainer::AddFrame was called, ancestors before children).

In order to support dynamic sticky changes without reframing, we need to
handle the case of an existing ancestor switching position to sticky
dynamically.

Luckily we already have the right data-structure for that, so the change
is rather trivial.

Write a testharness test for this because APZ does get the position
right, so it's more future-proof against regressions to just test the
raw layout values.

Differential Revision: https://phabricator.services.mozilla.com/D216858
2024-07-18 20:54:13 +00:00

70 lines
2.2 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_DepthOrderedFrameList_h
#define mozilla_DepthOrderedFrameList_h
#include "mozilla/ReverseIterator.h"
#include "nsTArray.h"
class nsIFrame;
namespace mozilla {
class DepthOrderedFrameList {
public:
// Add a dirty root.
void Add(nsIFrame* aFrame);
// Remove this frame if present.
void Remove(nsIFrame* aFrame);
// Remove and return one of the shallowest dirty roots from the list.
// (If two roots are at the same depth, order is indeterminate.)
nsIFrame* PopShallowestRoot();
// Remove all dirty roots.
void Clear() { mList.Clear(); }
// Is this frame one of the elements in the list?
bool Contains(nsIFrame* aFrame) const { return mList.Contains(aFrame); }
// Are there no elements?
bool IsEmpty() const { return mList.IsEmpty(); }
// Is the given frame an ancestor of any dirty root?
bool FrameIsAncestorOfAnyElement(nsIFrame* aFrame) const;
auto IterFromShallowest() const { return Reversed(mList); }
// The number of elements that there are.
size_t Length() const { return mList.Length(); }
nsIFrame* ElementAt(size_t i) const { return mList.ElementAt(i); }
void RemoveElementAt(size_t i) { mList.RemoveElementAt(i); }
private:
struct FrameAndDepth {
nsIFrame* mFrame;
const uint32_t mDepth;
// Easy conversion to nsIFrame*, as it's the most likely need.
operator nsIFrame*() const { return mFrame; }
// Used to sort by reverse depths, i.e., deeper < shallower.
class CompareByReverseDepth {
public:
bool Equals(const FrameAndDepth& aA, const FrameAndDepth& aB) const {
return aA.mDepth == aB.mDepth;
}
bool LessThan(const FrameAndDepth& aA, const FrameAndDepth& aB) const {
// Reverse depth! So '>' instead of '<'.
return aA.mDepth > aB.mDepth;
}
};
};
// List of all known dirty roots, sorted by decreasing depths.
nsTArray<FrameAndDepth> mList;
};
} // namespace mozilla
#endif