瀏覽代碼

Render table elements in proper order, bottom-to-top: columns, rows, cells.

Michael Ragazzon 5 年之前
父節點
當前提交
2a65287f61
共有 2 個文件被更改,包括 68 次插入51 次删除
  1. 63 49
      Source/Core/Element.cpp
  2. 5 2
      Tests/Data/VisualTests/table_01.rml

+ 63 - 49
Source/Core/Element.cpp

@@ -66,33 +66,6 @@
 
 namespace Rml {
 
-/**
-	STL function object for sorting elements by z-type (ie, float-types before general types, etc).
-	@author Peter Curry
- */
-class ElementSortZOrder
-{
-public:
-	bool operator()(const Pair< Element*, float >& lhs, const Pair< Element*, float >& rhs) const
-	{
-		return lhs.second < rhs.second;
-	}
-};
-
-/**
-	STL function object for sorting elements by z-index property.
-	@author Peter Curry
- */
-class ElementSortZIndex
-{
-public:
-	bool operator()(const Element* lhs, const Element* rhs) const
-	{
-		// Check the z-index.
-		return lhs->GetZIndex() < rhs->GetZIndex();
-	}
-};
-
 // Determines how many levels up in the hierarchy the OnChildAdd and OnChildRemove are called (starting at the child itself)
 static constexpr int ChildNotifyLevels = 2;
 
@@ -2162,7 +2135,7 @@ void Element::BuildLocalStackingContext()
 	stacking_context.clear();
 
 	BuildStackingContext(&stacking_context);
-	std::stable_sort(stacking_context.begin(), stacking_context.end(), ElementSortZIndex());
+	std::stable_sort(stacking_context.begin(), stacking_context.end(), [](const Element* lhs, const Element* rhs) { return lhs->GetZIndex() < rhs->GetZIndex(); });
 }
 
 void Element::BuildStackingContext(ElementList* new_stacking_context)
@@ -2172,52 +2145,93 @@ void Element::BuildStackingContext(ElementList* new_stacking_context)
 	// 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< Pair< Element*, float > > ordered_children;
-	for (size_t i = 0; i < children.size(); ++i)
+
+	enum class RenderOrder { Block, TableColumn, TableRow, TableCell, Inline, Floating, Positioned };
+
+	struct OrderedChild {
+		Element* element;
+		RenderOrder order;
+		bool include_children;
+	};
+	Vector< OrderedChild > ordered_children;
+	
+	const size_t num_children = children.size();
+	ordered_children.reserve(num_children);
+
+	const Style::Display current_display = GetDisplay();
+
+	for (size_t i = 0; i < num_children; ++i)
 	{
 		Element* child = children[i].get();
 
 		if (!child->IsVisible())
 			continue;
 
-		Pair< Element*, float > ordered_child;
-		ordered_child.first = child;
+		ordered_children.emplace_back();
+		OrderedChild& ordered_child = ordered_children.back();
+
+		ordered_child.element = child;
+		ordered_child.order = RenderOrder::Inline;
+		ordered_child.include_children = !child->local_stacking_context;
 
-		if (child->GetPosition() != Style::Position::Static)
-			ordered_child.second = 3;
-		else if (child->GetFloat() != Style::Float::None)
-			ordered_child.second = 1;
-		else if (child->GetDisplay() == Style::Display::Block)
-			ordered_child.second = 0;
+		const Style::Display child_display = child->GetDisplay();
+
+		if (current_display != Style::Display::Table)
+		{
+			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)
+				ordered_child.order = RenderOrder::Block;
+			else
+				ordered_child.order = RenderOrder::Inline;
+		}
 		else
-			ordered_child.second = 2;
+		{
+			// Tables always render columns first, then rows, then cells. Cells are treated as if they were direct descendents of the table.
+			if (child_display == Style::Display::TableColumn)
+			{
+				ordered_child.order = RenderOrder::TableColumn;
+				ordered_child.include_children = false;
+			}
+			else if (child_display == Style::Display::TableRow)
+			{
+				ordered_child.order = RenderOrder::TableRow;
+				ordered_child.include_children = false;
 
-		ordered_children.push_back(ordered_child);
+				for (const ElementPtr& row_child : child->children)
+				{
+					if (row_child->IsVisible() && row_child->GetDisplay() == Style::Display::TableCell)
+						ordered_children.emplace_back(OrderedChild{ row_child.get(), RenderOrder::TableCell, !row_child->local_stacking_context });
+				}
+			}
+		}
 	}
 
 	// Sort the list!
-	std::stable_sort(ordered_children.begin(), ordered_children.end(), ElementSortZOrder());
+	std::stable_sort(ordered_children.begin(), ordered_children.end(), [](const OrderedChild& lhs, const OrderedChild& rhs) { return int(lhs.order) < int(rhs.order); });
 
 	// Add the list of ordered children into the stacking context in order.
 	for (size_t i = 0; i < ordered_children.size(); ++i)
 	{
-		new_stacking_context->push_back(ordered_children[i].first);
+		new_stacking_context->push_back(ordered_children[i].element);
 
-		if (!ordered_children[i].first->local_stacking_context)
-			ordered_children[i].first->BuildStackingContext(new_stacking_context);
+		if (ordered_children[i].include_children)
+			ordered_children[i].element->BuildStackingContext(new_stacking_context);
 	}
 }
 
 void Element::DirtyStackingContext()
 {
-	// The first ancestor of ours that doesn't have an automatic z-index is the ancestor that is establishing our local
-	// stacking context.
+	// Find the first ancestor that has a local stacking context, that is our stacking context parent.
 	Element* stacking_context_parent = this;
-	while (stacking_context_parent != nullptr &&
-		   !stacking_context_parent->local_stacking_context)
+	while (stacking_context_parent && !stacking_context_parent->local_stacking_context)
+	{
 		stacking_context_parent = stacking_context_parent->GetParentNode();
+	}
 
-	if (stacking_context_parent != nullptr)
+	if (stacking_context_parent)
 		stacking_context_parent->stacking_context_dirty = true;
 }
 

+ 5 - 2
Tests/Data/VisualTests/table_01.rml

@@ -27,10 +27,13 @@
 			border: 5px #666;
 			gap: 10px 2%;
 			height: 50%;
+			padding-left: 5px;
+			padding-right: 20px;
 		}
 		col {
 			box-sizing: border-box;
 			display: table-column;
+			background: #aac;
 			border-left: 2px #e3e;
 			border-right: 5px #3ce;
 			margin: 15px 0;
@@ -44,8 +47,8 @@
 		tr {
 			box-sizing: border-box;
 			display: table-row;
-			border-bottom: 5px #ec3;
-			/*background: #3cc;*/
+			border-top: 5px #ec3;
+			background: #acc;
 			padding-top: 5px;
 			padding-bottom: 15px;
 			margin: 10px 20px;