mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 10:40:20 +03:00
Add CSS paint ordering and stacking contexts to HTML widgets
Implement spec-oriented paint phases for normal flow, floats, and positioned descendants, including atomic stacking groups and applicable z-index handling for flex and grid items. Share cached ordering between drawing and hit testing, propagate invalidation across stacking scopes, and preserve ancestor transforms and clipping for promoted descendants. Add regression coverage for paint order, hit testing, reparenting, clipping, flex ordering, and the old Reddit layout. Document the supported stacking model and remove the completed implementation plan.
This commit is contained in:
@@ -12,6 +12,7 @@ class RichText;
|
||||
namespace EE { namespace UI {
|
||||
|
||||
class UILayouter;
|
||||
class UIHTMLWidget;
|
||||
|
||||
enum class CSSFormattingRole : Uint8 {
|
||||
Inline,
|
||||
@@ -30,6 +31,16 @@ struct CSSUsedMargins {
|
||||
Uint8 autoSides{ 0 };
|
||||
};
|
||||
|
||||
struct CSSZIndex {
|
||||
int value{ 0 };
|
||||
bool isAuto{ true };
|
||||
|
||||
bool operator==( const CSSZIndex& other ) const {
|
||||
return value == other.value && isAuto == other.isAuto;
|
||||
}
|
||||
bool operator!=( const CSSZIndex& other ) const { return !( *this == other ); }
|
||||
};
|
||||
|
||||
struct UIHTMLWidgetFlexState {
|
||||
CSSFlexDirection direction{ CSSFlexDirection::Row };
|
||||
CSSFlexWrap wrap{ CSSFlexWrap::NoWrap };
|
||||
@@ -62,6 +73,22 @@ struct UIHTMLWidgetGridState {
|
||||
CSSJustifySelf justifySelf{ CSSJustifySelf::Auto };
|
||||
};
|
||||
|
||||
enum class HTMLPaintCategory : Uint8 {
|
||||
NegativePositioned,
|
||||
NormalFlow,
|
||||
Float,
|
||||
PositionedAutoOrZero,
|
||||
PositivePositioned,
|
||||
};
|
||||
|
||||
struct UIHTMLPaintOrderCache {
|
||||
SmallVector<Node*, 16> items;
|
||||
Uint32 rebuildCount{ 0 };
|
||||
bool dirty{ true };
|
||||
};
|
||||
|
||||
using UIHTMLPaintAncestorVector = SmallVector<UIHTMLWidget*, 8>;
|
||||
|
||||
class EE_API UIHTMLWidget : public UILayout {
|
||||
public:
|
||||
static UIHTMLWidget* New();
|
||||
@@ -131,10 +158,22 @@ class EE_API UIHTMLWidget : public UILayout {
|
||||
|
||||
void setOffsets( const Rectf& offsets );
|
||||
|
||||
int getZIndex() const { return mZIndex; }
|
||||
const CSSZIndex& getCSSZIndex() const { return mZIndex; }
|
||||
|
||||
bool hasAutoZIndex() const { return mZIndex.isAuto; }
|
||||
|
||||
int getZIndex() const { return mZIndex.value; }
|
||||
|
||||
void setZIndex( int zIndex );
|
||||
|
||||
void setZIndexAuto();
|
||||
|
||||
bool isCSSPositioned() const { return mPosition != CSSPosition::Static; }
|
||||
|
||||
bool hasApplicableZIndex() const;
|
||||
|
||||
bool createsSupportedStackingGroup() const;
|
||||
|
||||
bool getNeedsOrderSort() const { return mNeedsOrderSort; }
|
||||
|
||||
void setNeedsOrderSort( bool val );
|
||||
@@ -308,10 +347,16 @@ class EE_API UIHTMLWidget : public UILayout {
|
||||
|
||||
virtual void onChildCountChange( Node* child, const bool& removed );
|
||||
|
||||
void updateZIndexSortFlag();
|
||||
|
||||
void buildDrawOrderVector( SmallVector<Node*, 127>& out ) const;
|
||||
|
||||
Uint32 getPaintOrderRebuildCount() const;
|
||||
|
||||
std::vector<Node*> debugGetHTMLPaintOrder() const;
|
||||
|
||||
std::vector<Node*> debugGetHTMLHitTestOrder() const;
|
||||
|
||||
bool isHTMLPaintPromoted() const { return mHTMLPaintOwner != nullptr; }
|
||||
|
||||
Float getBaseline() const;
|
||||
|
||||
Float getContainingBlockContentWidth() const;
|
||||
@@ -389,14 +434,20 @@ class EE_API UIHTMLWidget : public UILayout {
|
||||
std::string mBottomEq{ "auto" };
|
||||
std::string mLeftEq{ "auto" };
|
||||
Rectf mOffsets{ 0, 0, 0, 0 };
|
||||
int mZIndex{ 0 };
|
||||
CSSZIndex mZIndex;
|
||||
bool mOverflowCreatesBlockFormattingContext{ false };
|
||||
bool mNeedsOrderSort{ false };
|
||||
bool mNeedsZIndexSort{ false };
|
||||
bool mNeedsPaintOrder{ false };
|
||||
bool mHasStackingDescendant{ false };
|
||||
mutable bool mHasPromotedChild{ false };
|
||||
mutable bool mHasActivePromotions{ false };
|
||||
Uint8 mPercentageMargins{ 0 };
|
||||
UILayouter* mLayouter{ nullptr };
|
||||
UIHTMLWidgetFlexState* mFlexState{ nullptr };
|
||||
UIHTMLWidgetGridState* mGridState{ nullptr };
|
||||
mutable UIHTMLPaintOrderCache* mPaintOrderCache{ nullptr };
|
||||
mutable const UIHTMLWidget* mHTMLPaintOwner{ nullptr };
|
||||
mutable UIHTMLPaintAncestorVector* mHTMLPaintAncestors{ nullptr };
|
||||
UnorderedMap<std::string, StyleSheetProperty> mDataProperties;
|
||||
|
||||
Uint32 mScrollCb{ 0 };
|
||||
@@ -406,6 +457,22 @@ class EE_API UIHTMLWidget : public UILayout {
|
||||
|
||||
void updateScrollListeners();
|
||||
void onScrollTargetPositionChange();
|
||||
void invalidatePaintOrder();
|
||||
void updatePaintOrderFlag();
|
||||
const SmallVector<Node*, 16>& getPaintOrder() const;
|
||||
bool isHTMLStackingScope() const;
|
||||
void buildCSSChildOrder( SmallVector<Node*, 16>& out ) const;
|
||||
void resetPromotedPaintState() const;
|
||||
void collectStackingScopeItems( UIHTMLWidget* container, SmallVector<Node*, 16>& out,
|
||||
bool directChildren ) const;
|
||||
void collectStackingScopeChild( Node* child, SmallVector<Node*, 16>& out,
|
||||
bool directChildren ) const;
|
||||
void promoteHTMLPaintNode( UIHTMLWidget* widget ) const;
|
||||
void drawHTMLPaintNode( Node* node );
|
||||
bool containsHTMLPaintClipPoint( const Vector2f& point ) const;
|
||||
bool canHitHTMLPaintNode( Node* node, const Vector2f& point ) const;
|
||||
bool needsHTMLPaintTraversal() const;
|
||||
bool shouldSkipHTMLPaintNode( Node* node ) const;
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
Reference in New Issue
Block a user