|
|
@@ -2263,128 +2263,159 @@ void Element::SetBaseline(float in_baseline)
|
|
|
baseline = in_baseline;
|
|
|
}
|
|
|
|
|
|
-void Element::BuildLocalStackingContext()
|
|
|
+enum class RenderOrder {
|
|
|
+ StackNegative, // Local stacking context with z < 0.
|
|
|
+ Block,
|
|
|
+ TableColumnGroup,
|
|
|
+ TableColumn,
|
|
|
+ TableRowGroup,
|
|
|
+ TableRow,
|
|
|
+ TableCell,
|
|
|
+ Floating,
|
|
|
+ Inline,
|
|
|
+ Positioned, // Positioned element, or local stacking context with z == 0.
|
|
|
+ StackPositive, // Local stacking context with z > 0.
|
|
|
+};
|
|
|
+struct StackingContextChild {
|
|
|
+ Element* element = nullptr;
|
|
|
+ RenderOrder order = {};
|
|
|
+};
|
|
|
+static bool operator<(const StackingContextChild& lhs, const StackingContextChild& rhs)
|
|
|
{
|
|
|
- stacking_context_dirty = false;
|
|
|
- stacking_context.clear();
|
|
|
-
|
|
|
- BuildStackingContext(&stacking_context);
|
|
|
- std::stable_sort(stacking_context.begin(), stacking_context.end(), [](const Element* lhs, const Element* rhs) { return lhs->GetZIndex() < rhs->GetZIndex(); });
|
|
|
+ if (int(lhs.order) == int(rhs.order))
|
|
|
+ return lhs.element->GetZIndex() < rhs.element->GetZIndex();
|
|
|
+ return int(lhs.order) < int(rhs.order);
|
|
|
}
|
|
|
|
|
|
-enum class RenderOrder { Block, TableColumnGroup, TableColumn, TableRowGroup, TableRow, TableCell, Inline, Floating, Positioned };
|
|
|
-struct StackingOrderedChild {
|
|
|
- Element* element;
|
|
|
- RenderOrder order;
|
|
|
- bool include_children;
|
|
|
-};
|
|
|
-
|
|
|
-void Element::BuildStackingContext(ElementList* new_stacking_context)
|
|
|
+// Treat all children in the range [index_begin, end) as if the parent created a new stacking context, by sorting them
|
|
|
+// separately and then assigning their parent's paint order. However, positioned and descendants which create a new
|
|
|
+// stacking context should be considered part of the parent stacking context. See CSS 2, Appendix E.
|
|
|
+static void StackingContext_MakeAtomicRange(Vector<StackingContextChild>& stacking_children, size_t index_begin, RenderOrder parent_render_order)
|
|
|
{
|
|
|
- RMLUI_ZoneScoped;
|
|
|
-
|
|
|
- // Build the list of ordered children. Our child list is sorted within the stacking context so stacked elements
|
|
|
- // will render in the right order; ie, positioned elements will render on top of inline elements, which will render
|
|
|
- // on top of floated elements, which will render on top of block elements.
|
|
|
- Vector< StackingOrderedChild > ordered_children;
|
|
|
+ std::stable_sort(stacking_children.begin() + index_begin, stacking_children.end());
|
|
|
|
|
|
- const size_t num_children = children.size();
|
|
|
- ordered_children.reserve(num_children);
|
|
|
-
|
|
|
- if (GetDisplay() == Style::Display::Table)
|
|
|
+ for (auto it = stacking_children.begin() + index_begin; it != stacking_children.end(); ++it)
|
|
|
{
|
|
|
- BuildStackingContextForTable(ordered_children, this);
|
|
|
+ auto order = it->order;
|
|
|
+ if (order != RenderOrder::StackNegative && order != RenderOrder::Positioned && order != RenderOrder::StackPositive)
|
|
|
+ it->order = parent_render_order;
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- for (size_t i = 0; i < num_children; ++i)
|
|
|
- {
|
|
|
- Element* child = children[i].get();
|
|
|
-
|
|
|
- if (!child->IsVisible())
|
|
|
- continue;
|
|
|
-
|
|
|
- ordered_children.emplace_back();
|
|
|
- StackingOrderedChild& ordered_child = ordered_children.back();
|
|
|
-
|
|
|
- ordered_child.element = child;
|
|
|
- ordered_child.order = RenderOrder::Inline;
|
|
|
- ordered_child.include_children = !child->local_stacking_context;
|
|
|
+}
|
|
|
|
|
|
- const Style::Display child_display = child->GetDisplay();
|
|
|
+void Element::BuildLocalStackingContext()
|
|
|
+{
|
|
|
+ stacking_context_dirty = false;
|
|
|
|
|
|
- if (child->GetPosition() != Style::Position::Static)
|
|
|
- ordered_child.order = RenderOrder::Positioned;
|
|
|
- else if (child->GetFloat() != Style::Float::None)
|
|
|
- ordered_child.order = RenderOrder::Floating;
|
|
|
- else if (child_display == Style::Display::Block || child_display == Style::Display::Table || child_display == Style::Display::Flex)
|
|
|
- ordered_child.order = RenderOrder::Block;
|
|
|
- else
|
|
|
- ordered_child.order = RenderOrder::Inline;
|
|
|
- }
|
|
|
- }
|
|
|
+ Vector<StackingContextChild> stacking_children;
|
|
|
+ AddChildrenToStackingContext(stacking_children);
|
|
|
+ std::stable_sort(stacking_children.begin(), stacking_children.end());
|
|
|
|
|
|
- // Sort the list!
|
|
|
- std::stable_sort(ordered_children.begin(), ordered_children.end(), [](const StackingOrderedChild& lhs, const StackingOrderedChild& rhs) { return int(lhs.order) < int(rhs.order); });
|
|
|
+ stacking_context.resize(stacking_children.size());
|
|
|
+ for (size_t i = 0; i < stacking_children.size(); i++)
|
|
|
+ stacking_context[i] = stacking_children[i].element;
|
|
|
+}
|
|
|
|
|
|
- // Add the list of ordered children into the stacking context in order.
|
|
|
- for (size_t i = 0; i < ordered_children.size(); ++i)
|
|
|
+void Element::AddChildrenToStackingContext(Vector<StackingContextChild>& stacking_children)
|
|
|
+{
|
|
|
+ bool is_flex_container = (GetDisplay() == Style::Display::Flex);
|
|
|
+ const int num_children = (int)children.size();
|
|
|
+ for (int i = 0; i < num_children; ++i)
|
|
|
{
|
|
|
- new_stacking_context->push_back(ordered_children[i].element);
|
|
|
-
|
|
|
- if (ordered_children[i].include_children)
|
|
|
- ordered_children[i].element->BuildStackingContext(new_stacking_context);
|
|
|
+ const bool is_non_dom_element = (i >= num_children - num_non_dom_children);
|
|
|
+ children[i]->AddToStackingContext(stacking_children, is_flex_container, is_non_dom_element);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void Element::BuildStackingContextForTable(Vector<StackingOrderedChild>& ordered_children, Element* parent)
|
|
|
+void Element::AddToStackingContext(Vector<StackingContextChild>& stacking_children, bool is_flex_item, bool is_non_dom_element)
|
|
|
{
|
|
|
- const size_t num_children = parent->children.size();
|
|
|
+ using Style::Display;
|
|
|
|
|
|
- for (size_t i = 0; i < num_children; ++i)
|
|
|
- {
|
|
|
- Element* child = parent->children[i].get();
|
|
|
+ if (!IsVisible())
|
|
|
+ return;
|
|
|
|
|
|
- if (!child->IsVisible())
|
|
|
- continue;
|
|
|
+ const Display display = GetDisplay();
|
|
|
|
|
|
- ordered_children.emplace_back();
|
|
|
- StackingOrderedChild& ordered_child = ordered_children.back();
|
|
|
- ordered_child.element = child;
|
|
|
- ordered_child.order = RenderOrder::Inline;
|
|
|
- ordered_child.include_children = false;
|
|
|
+ RenderOrder order = RenderOrder::Inline;
|
|
|
+ bool include_children = true;
|
|
|
+ bool render_as_atomic_unit = false;
|
|
|
|
|
|
- bool recurse_into_children = false;
|
|
|
+ if (local_stacking_context)
|
|
|
+ {
|
|
|
+ if (z_index > 0.f)
|
|
|
+ order = RenderOrder::StackPositive;
|
|
|
+ else if (z_index < 0.f)
|
|
|
+ order = RenderOrder::StackNegative;
|
|
|
+ else
|
|
|
+ order = RenderOrder::Positioned;
|
|
|
|
|
|
- switch (child->GetDisplay())
|
|
|
+ include_children = false;
|
|
|
+ }
|
|
|
+ else if (display == Display::TableRow || display == Display::TableRowGroup || display == Display::TableColumn ||
|
|
|
+ display == Display::TableColumnGroup)
|
|
|
+ {
|
|
|
+ // Handle internal display values taking priority over position and float.
|
|
|
+ switch (display)
|
|
|
{
|
|
|
- case Style::Display::TableRow:
|
|
|
- ordered_child.order = RenderOrder::TableRow;
|
|
|
- recurse_into_children = true;
|
|
|
- break;
|
|
|
- case Style::Display::TableRowGroup:
|
|
|
- ordered_child.order = RenderOrder::TableRowGroup;
|
|
|
- recurse_into_children = true;
|
|
|
- break;
|
|
|
- case Style::Display::TableColumn:
|
|
|
- ordered_child.order = RenderOrder::TableColumn;
|
|
|
- break;
|
|
|
- case Style::Display::TableColumnGroup:
|
|
|
- ordered_child.order = RenderOrder::TableColumnGroup;
|
|
|
- recurse_into_children = true;
|
|
|
+ case Display::TableRow: order = RenderOrder::TableRow; break;
|
|
|
+ case Display::TableRowGroup: order = RenderOrder::TableRowGroup; break;
|
|
|
+ case Display::TableColumn: order = RenderOrder::TableColumn; break;
|
|
|
+ case Display::TableColumnGroup: order = RenderOrder::TableColumnGroup; break;
|
|
|
+ default: break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (GetPosition() != Style::Position::Static)
|
|
|
+ {
|
|
|
+ order = RenderOrder::Positioned;
|
|
|
+ render_as_atomic_unit = true;
|
|
|
+ }
|
|
|
+ else if (GetFloat() != Style::Float::None)
|
|
|
+ {
|
|
|
+ order = RenderOrder::Floating;
|
|
|
+ render_as_atomic_unit = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ switch (display)
|
|
|
+ {
|
|
|
+ case Display::Block:
|
|
|
+ case Display::Table:
|
|
|
+ case Display::Flex:
|
|
|
+ order = RenderOrder::Block;
|
|
|
+ render_as_atomic_unit = (display == Display::Table || is_flex_item);
|
|
|
break;
|
|
|
- case Style::Display::TableCell:
|
|
|
- ordered_child.order = RenderOrder::TableCell;
|
|
|
- ordered_child.include_children = !child->local_stacking_context;
|
|
|
+
|
|
|
+ case Display::Inline:
|
|
|
+ case Display::InlineBlock:
|
|
|
+ order = RenderOrder::Inline;
|
|
|
+ render_as_atomic_unit = (display == Display::InlineBlock || is_flex_item);
|
|
|
break;
|
|
|
- default:
|
|
|
- ordered_child.order = RenderOrder::Positioned;
|
|
|
- ordered_child.include_children = !child->local_stacking_context;
|
|
|
+
|
|
|
+ case Display::TableCell:
|
|
|
+ order = RenderOrder::TableCell;
|
|
|
+ render_as_atomic_unit = true;
|
|
|
break;
|
|
|
+
|
|
|
+ case Display::TableRow:
|
|
|
+ case Display::TableRowGroup:
|
|
|
+ case Display::TableColumn:
|
|
|
+ case Display::TableColumnGroup:
|
|
|
+ case Display::None: RMLUI_ERROR; break; /* Handled above */
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ if (is_non_dom_element)
|
|
|
+ render_as_atomic_unit = true;
|
|
|
+
|
|
|
+ stacking_children.push_back(StackingContextChild{this, order});
|
|
|
+
|
|
|
+ if (include_children && !children.empty())
|
|
|
+ {
|
|
|
+ const size_t index_child_begin = stacking_children.size();
|
|
|
+
|
|
|
+ AddChildrenToStackingContext(stacking_children);
|
|
|
|
|
|
- if (recurse_into_children)
|
|
|
- BuildStackingContextForTable(ordered_children, child);
|
|
|
+ if (render_as_atomic_unit)
|
|
|
+ StackingContext_MakeAtomicRange(stacking_children, index_child_begin, order);
|
|
|
}
|
|
|
}
|
|
|
|