Browse Source

Node and Element: Change to new behavior for previously deprecated functions

Rename usage of previously deprecated functions to use the new names.
Michael Ragazzon 4 weeks ago
parent
commit
aeedbb43cb
43 changed files with 245 additions and 237 deletions
  1. 2 2
      CMake/Utilities.cmake
  2. 0 4
      Include/RmlUi/Core/Element.h
  3. 30 8
      Include/RmlUi/Core/Node.h
  4. 1 1
      Samples/basic/demo/src/DemoEventListener.cpp
  5. 1 2
      Samples/basic/demo/src/DemoWindow.cpp
  6. 7 8
      Samples/basic/drag/src/DragListener.cpp
  7. 1 1
      Samples/basic/drag/src/Inventory.cpp
  8. 1 1
      Samples/tutorial/drag/src/Inventory.cpp
  9. 11 11
      Source/Core/Context.cpp
  10. 2 2
      Source/Core/DataModel.cpp
  11. 1 1
      Source/Core/DataView.cpp
  12. 7 26
      Source/Core/Element.cpp
  13. 7 7
      Source/Core/ElementDocument.cpp
  14. 1 1
      Source/Core/ElementHandle.cpp
  15. 4 5
      Source/Core/ElementScroll.cpp
  16. 3 3
      Source/Core/ElementStyle.cpp
  17. 2 2
      Source/Core/ElementText.cpp
  18. 1 1
      Source/Core/ElementUtilities.cpp
  19. 2 2
      Source/Core/Elements/ElementFormControlSelect.cpp
  20. 3 3
      Source/Core/Elements/ElementProgress.cpp
  21. 8 8
      Source/Core/Elements/ElementTabSet.cpp
  22. 3 3
      Source/Core/Elements/InputTypeRadio.cpp
  23. 2 2
      Source/Core/Elements/InputTypeSubmit.cpp
  24. 10 10
      Source/Core/Elements/WidgetDropDown.cpp
  25. 5 16
      Source/Core/Elements/WidgetSlider.cpp
  26. 1 1
      Source/Core/Elements/XMLNodeHandlerTextArea.cpp
  27. 1 1
      Source/Core/EventDispatcher.cpp
  28. 1 1
      Source/Core/Layout/FormattingContext.cpp
  29. 56 25
      Source/Core/Node.cpp
  30. 2 2
      Source/Core/StyleSheetNode.cpp
  31. 10 10
      Source/Core/StyleSheetSelector.cpp
  32. 5 17
      Source/Core/WidgetScroll.cpp
  33. 1 1
      Source/Core/XMLNodeHandlerDefault.cpp
  34. 10 10
      Source/Debugger/ElementInfo.cpp
  35. 15 12
      Source/Debugger/ElementLog.cpp
  36. 7 7
      Source/Lua/Element.cpp
  37. 2 2
      Tests/Source/UnitTests/Core.cpp
  38. 2 2
      Tests/Source/UnitTests/DataBinding.cpp
  39. 10 9
      Tests/Source/UnitTests/Element.cpp
  40. 2 2
      Tests/Source/UnitTests/ElementImage.cpp
  41. 2 2
      Tests/Source/UnitTests/EventListener.cpp
  42. 2 2
      Tests/Source/UnitTests/Selectors.cpp
  43. 1 1
      Tests/Source/UnitTests/XMLParser.cpp

+ 2 - 2
CMake/Utilities.cmake

@@ -103,9 +103,9 @@ function(set_common_target_options target)
 
 	if(RMLUI_COMPILER_OPTIONS)
 		if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
-			target_compile_options(${target} PRIVATE -Wall -Wextra -pedantic -Wno-deprecated-declarations)
+			target_compile_options(${target} PRIVATE -Wall -Wextra -pedantic)
 		elseif(MSVC)
-			target_compile_options(${target} PRIVATE /W4 /w44062 /wd4458 /wd4251 /wd4996 /permissive-)
+			target_compile_options(${target} PRIVATE /W4 /w44062 /wd4458 /wd4251 /permissive-)
 			target_compile_definitions(${target} PRIVATE _CRT_SECURE_NO_WARNINGS)
 			if(CMAKE_GENERATOR MATCHES "Visual Studio")
 				target_compile_options(${target} PRIVATE /MP)

+ 0 - 4
Include/RmlUi/Core/Element.h

@@ -431,20 +431,16 @@ public:
 	/// Gets the element immediately following this one in the tree.
 	/// @return This element's next sibling element, or nullptr if there is no sibling element.
 	Element* GetNextElementSibling() const;
-	[[deprecated("Use GetNextElementSibling")]] Element* GetNextSibling() const;
 	/// Gets the element immediately preceding this one in the tree.
 	/// @return This element's previous sibling element, or nullptr if there is no sibling element.
 	Element* GetPreviousElementSibling() const;
-	[[deprecated("Use GetPreviousElementSibling")]] Element* GetPreviousSibling() const;
 
 	/// Returns the first child of this element.
 	/// @return This element's first child, or nullptr if it contains no children.
 	Element* GetFirstElementChild() const;
-	[[deprecated("Use GetFirstElementChild")]] Element* GetFirstChild() const;
 	/// Gets the last child of this element.
 	/// @return This element's last child, or nullptr if it contains no children.
 	Element* GetLastElementChild() const;
-	[[deprecated("Use GetLastElementChild")]] Element* GetLastChild() const;
 	/// Get the child element at the given index.
 	/// @param[in] index Index of child to get.
 	/// @return The child element at the given index.

+ 30 - 8
Include/RmlUi/Core/Node.h

@@ -39,6 +39,7 @@ class Context;
 class Element;
 class ElementDocument;
 class NodeInstancer;
+class NodePtrProxy;
 using OwnedNodeList = Vector<NodePtr>;
 
 /**
@@ -62,34 +63,43 @@ public:
 	/// @return True if the node has at least one DOM child, false otherwise.
 	bool HasChildNodes() const;
 
+	/// Returns the first child of this node.
+	/// @return This node's first child, or nullptr if it contains no children.
+	Node* GetFirstChild() const;
+	/// Gets the last child of this node.
+	/// @return This node's last child, or nullptr if it contains no children.
+	Node* GetLastChild() const;
+	/// Gets the node immediately following this one in the tree.
+	/// @return This node's next sibling node, or nullptr if there is no sibling node.
+	Node* GetNextSibling() const;
+	/// Gets the node immediately preceding this one in the tree.
+	/// @return This node's previous sibling node, or nullptr if there is no sibling node.
+	Node* GetPreviousSibling() const;
+
 	/// Append a child to this node.
 	/// @param[in] node The node to append as a child.
 	/// @param[in] dom_node True if the node is to be part of the DOM, false otherwise. Only set this to false if you know what you're doing!
 	/// @return A pointer to the just inserted node.
-	Node* AppendChild(NodePtr node, bool dom_node = true);
-	[[deprecated("Use the NodePtr version of this function")]] Element* AppendChild(ElementPtr element, bool dom_element = true);
+	Node* AppendChild(NodePtrProxy node, bool dom_node = true);
 	/// Adds a child to this node directly before the adjacent node. The new node inherits the DOM/non-DOM
 	/// status from the adjacent node.
 	/// @param[in] node Node to be inserted.
 	/// @param[in] adjacent_node The reference node which the new node will be inserted before.
 	/// @return A pointer to the just inserted node.
-	Node* InsertBefore(NodePtr node, Node* adjacent_node);
-	[[deprecated("Use the NodePtr version of this function")]] Element* InsertBefore(ElementPtr element, Element* adjacent_element);
+	Node* InsertBefore(NodePtrProxy node, Node* adjacent_node);
 	/// Replaces the second node with the first node.
 	/// @param[in] insert_node The node to insert and replace the other node.
 	/// @param[in] replace_node The existing child node to replace. If this doesn't exist, insert_node will be appended.
 	/// @return A unique pointer to the replaced node if found, discard the result to immediately destroy.
-	NodePtr ReplaceChild(NodePtr insert_node, Node* replace_node);
-	[[deprecated("Use the NodePtr version of this function")]] ElementPtr ReplaceChild(ElementPtr inserted_element, Element* replaced_element);
+	NodePtr ReplaceChild(NodePtrProxy insert_node, Node* replace_node);
 	/// Remove a child node from this node.
 	/// @param[in] node The node to remove.
 	/// @return A unique pointer to the node if found, discard the result to immediately destroy.
 	NodePtr RemoveChild(Node* node);
-	[[deprecated("Use the NodePtr version of this function")]] ElementPtr RemoveChild(Element* element);
 
 	/// Gets this nodes's parent node.
 	/// @return This node's parent.
-	[[deprecated("Use GetParentElement")]] Element* GetParentNode() const;
+	Node* GetParentNode() const;
 	/// Gets this nodes's parent element.
 	/// @return This node's parent if it is an element, otherwise false.
 	Element* GetParentElement() const;
@@ -308,6 +318,18 @@ private:
 	friend class Rml::Context;
 };
 
+class RMLUICORE_API NodePtrProxy {
+public:
+	NodePtrProxy(NodePtr node);
+	NodePtrProxy(ElementPtr element);
+	Node* Get();
+	NodePtr Extract();
+	explicit operator bool() const;
+
+private:
+	NodePtr node;
+};
+
 } // namespace Rml
 
 #endif

+ 1 - 1
Samples/basic/demo/src/DemoEventListener.cpp

@@ -53,7 +53,7 @@ void DemoEventListener::ProcessEvent(Rml::Event& event)
 	else if (value == "move_child")
 	{
 		const Vector2f mouse_pos = {event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f)};
-		if (Element* child = element->GetFirstChild())
+		if (Element* child = element->GetFirstElementChild())
 		{
 			Vector2f new_pos = mouse_pos - element->GetAbsoluteOffset() - Vector2f(0.35f * child->GetClientWidth(), 0.9f * child->GetClientHeight());
 			Property destination = Transform::MakeProperty({Transforms::Translate2D(new_pos.x, new_pos.y)});

+ 1 - 2
Samples/basic/demo/src/DemoWindow.cpp

@@ -72,8 +72,7 @@ bool DemoWindow::Initialize(const Rml::String& title, Rml::Context* context)
 	if (auto target = document->GetElementById("sandbox_target"))
 	{
 		iframe = context->CreateDocument();
-		auto iframe_ptr = iframe->GetParentNode()->RemoveChild(iframe);
-		target->AppendChild(std::move(iframe_ptr));
+		target->AppendChild(iframe->Remove());
 		iframe->SetProperty(PropertyId::Position, Property(Style::Position::Absolute));
 		iframe->SetProperty(PropertyId::Display, Property(Style::Display::Block));
 		iframe->SetInnerRML("<p>Rendered output goes here.</p>");

+ 7 - 8
Samples/basic/drag/src/DragListener.cpp

@@ -47,8 +47,7 @@ void DragListener::ProcessEvent(Rml::Event& event)
 		if (dest_container == dest_element)
 		{
 			// The dragged element was dragged directly onto a container.
-			Rml::ElementPtr element = drag_element->GetParentNode()->RemoveChild(drag_element);
-			dest_container->AppendChild(std::move(element));
+			dest_container->AppendChild(drag_element->Remove());
 		}
 		else
 		{
@@ -59,25 +58,25 @@ void DragListener::ProcessEvent(Rml::Event& event)
 
 			// Unless of course if it was dragged on top of an item in its own container; we need
 			// to check then if it was moved up or down with the container.
-			if (drag_element->GetParentNode() == dest_container)
+			if (drag_element->GetParentElement() == dest_container)
 			{
 				// Check whether we're moving this icon from the left or the right.
 
-				Rml::Element* previous_icon = insert_before->GetPreviousSibling();
+				Rml::Element* previous_icon = insert_before->GetPreviousElementSibling();
 				while (previous_icon != nullptr)
 				{
 					if (previous_icon == drag_element)
 					{
-						insert_before = insert_before->GetNextSibling();
+						insert_before = insert_before->GetNextElementSibling();
 						break;
 					}
 
-					previous_icon = previous_icon->GetPreviousSibling();
+					previous_icon = previous_icon->GetPreviousElementSibling();
 				}
 			}
 
-			Rml::ElementPtr element = drag_element->GetParentNode()->RemoveChild(drag_element);
-			dest_container->InsertBefore(std::move(element), insert_before);
+			Rml::NodePtr node = drag_element->GetParentElement()->RemoveChild(drag_element);
+			dest_container->InsertBefore(std::move(node), insert_before);
 		}
 	}
 }

+ 1 - 1
Samples/basic/drag/src/Inventory.cpp

@@ -63,6 +63,6 @@ void Inventory::AddItem(const Rml::String& name)
 		return;
 
 	// Create the new 'icon' element.
-	Rml::Element* icon = content->AppendChild(Rml::As<Rml::ElementPtr>(Rml::Factory::InstanceNode("icon", "icon")));
+	Rml::Element* icon = Rml::As<Rml::Element*>(content->AppendChild(Rml::Factory::InstanceNode("icon", "icon")));
 	icon->SetInnerRML(name);
 }

+ 1 - 1
Samples/tutorial/drag/src/Inventory.cpp

@@ -29,6 +29,6 @@ void Inventory::AddItem(const Rml::String& name)
 		return;
 
 	// Create the new 'icon' element.
-	Rml::Element* icon = content->AppendChild(Rml::As<Rml::ElementPtr>(Rml::Factory::InstanceNode("icon", "icon")));
+	Rml::Element* icon = Rml::As<Rml::Element*>(content->AppendChild(Rml::Factory::InstanceNode("icon", "icon")));
 	icon->SetInnerRML(name);
 }

+ 11 - 11
Source/Core/Context.cpp

@@ -363,8 +363,8 @@ void Context::UnloadDocument(ElementDocument* _document)
 		document->DispatchEvent(EventId::Unload, Dictionary());
 		PluginRegistry::NotifyDocumentUnload(document);
 
-		// Move document to a temporary location to be released later.
-		unloaded_documents.push_back(root->RemoveChild(document));
+		// Remove from root and place document in a temporary location to be released later.
+		unloaded_documents.push_back(document->Remove());
 	}
 
 	// Remove the item from the focus history.
@@ -635,7 +635,7 @@ static Element* FindFocusElement(Element* element)
 
 	while (element && element->GetComputedValues().focus() == Style::Focus::None)
 	{
-		element = element->GetParentNode();
+		element = element->GetParentElement();
 	}
 
 	return element;
@@ -710,7 +710,7 @@ bool Context::ProcessMouseButtonDown(int button_index, int key_modifier_state)
 				Style::Drag drag_style = drag->GetComputedValues().drag();
 				switch (drag_style)
 				{
-				case Style::Drag::None: drag = drag->GetParentNode(); continue;
+				case Style::Drag::None: drag = drag->GetParentElement(); continue;
 				case Style::Drag::Block: drag = nullptr; continue;
 				default: drag_verbose = (drag_style == Style::Drag::DragDrop || drag_style == Style::Drag::Clone);
 				}
@@ -1233,7 +1233,7 @@ bool Context::OnFocusChange(Element* new_focus, bool focus_visible)
 	while (element)
 	{
 		old_chain.insert(element);
-		element = element->GetParentNode();
+		element = element->GetParentElement();
 	}
 
 	// Build the new chain
@@ -1241,7 +1241,7 @@ bool Context::OnFocusChange(Element* new_focus, bool focus_visible)
 	while (element)
 	{
 		new_chain.insert(element);
-		element = element->GetParentNode();
+		element = element->GetParentElement();
 	}
 
 	// Send out blur/focus events.
@@ -1353,7 +1353,7 @@ void Context::UpdateHoverChain(Vector2i old_mouse_position, int key_modifier_sta
 	while (element != nullptr)
 	{
 		new_hover_chain.insert(element);
-		element = element->GetParentNode();
+		element = element->GetParentElement();
 	}
 
 	// Send mouseout / mouseover events.
@@ -1370,7 +1370,7 @@ void Context::UpdateHoverChain(Vector2i old_mouse_position, int key_modifier_sta
 		while (element != nullptr)
 		{
 			new_drag_hover_chain.insert(element);
-			element = element->GetParentNode();
+			element = element->GetParentElement();
 		}
 
 		if (drag_started && drag_verbose)
@@ -1427,7 +1427,7 @@ Element* Context::GetElementAtPoint(Vector2f point, const Element* ignore_elemen
 					if (element_hierarchy == ignore_element)
 						break;
 
-					element_hierarchy = element_hierarchy->GetParentNode();
+					element_hierarchy = element_hierarchy->GetParentElement();
 				}
 
 				if (element_hierarchy)
@@ -1495,12 +1495,12 @@ void Context::CreateDragClone(Element* element)
 	drag_clone = element_drag_clone.get();
 
 	// Append the clone to the cursor proxy element.
-	cursor_proxy->AppendChild(std::move(element_drag_clone));
+	cursor_proxy->AppendChild(As<NodePtr>(std::move(element_drag_clone)));
 
 	// Position the clone. Use projected mouse coordinates to handle any ancestor transforms.
 	const Vector2f absolute_pos = element->GetAbsoluteOffset(BoxArea::Border);
 	Vector2f projected_mouse_position = Vector2f(mouse_position);
-	if (Element* parent = element->GetParentNode())
+	if (Element* parent = element->GetParentElement())
 		parent->Project(projected_mouse_position);
 
 	drag_clone->SetProperty(PropertyId::Position, Property(Style::Position::Absolute));

+ 2 - 2
Source/Core/DataModel.cpp

@@ -244,7 +244,7 @@ void DataModel::CopyAliases(Element* from_element, Element* to_element)
 	{
 		// Need to create a copy to prevent errors during concurrent modification for 3rd party containers
 		auto copy = existing_map->second;
-		for (auto const& it : copy)
+		for (const auto& it : copy)
 			aliases[to_element][it.first] = std::move(it.second);
 	}
 }
@@ -288,7 +288,7 @@ DataAddress DataModel::ResolveAddress(const String& address_str, Element* elemen
 			}
 		}
 
-		ancestor = ancestor->GetParentNode();
+		ancestor = ancestor->GetParentElement();
 	}
 
 	Log::Message(Log::LT_WARNING, "Could not find variable name '%s' in data model.", address_str.c_str());

+ 1 - 1
Source/Core/DataView.cpp

@@ -58,7 +58,7 @@ DataView::DataView(Element* element, int bias) : attached_element(element->GetOb
 
 	if (element)
 	{
-		for (Element* parent = element->GetParentNode(); parent; parent = parent->GetParentNode())
+		for (Node* parent = element->GetParentNode(); parent; parent = parent->GetParentNode())
 			sort_order += 2000;
 	}
 }

+ 7 - 26
Source/Core/Element.cpp

@@ -1011,7 +1011,7 @@ Element* Element::Closest(const String& selectors) const
 		return nullptr;
 	}
 
-	Element* parent = GetParentNode();
+	Element* parent = GetParentElement();
 
 	while (parent)
 	{
@@ -1023,7 +1023,7 @@ Element* Element::Closest(const String& selectors) const
 			}
 		}
 
-		parent = parent->GetParentNode();
+		parent = parent->GetParentElement();
 	}
 
 	return nullptr;
@@ -1064,15 +1064,6 @@ Element* Element::GetPreviousElementSibling() const
 	return nullptr;
 }
 
-Element* Element::GetNextSibling() const
-{
-	return GetNextElementSibling();
-}
-
-Element* Element::GetPreviousSibling() const
-{
-	return GetPreviousElementSibling();
-}
 Element* Element::GetFirstElementChild() const
 {
 	auto range = IterateChildren<Element>();
@@ -1082,11 +1073,6 @@ Element* Element::GetFirstElementChild() const
 	return *it;
 }
 
-Element* Element::GetFirstChild() const
-{
-	return GetFirstElementChild();
-}
-
 Element* Element::GetLastElementChild() const
 {
 	auto range = IterateChildrenReverse<Element>();
@@ -1096,11 +1082,6 @@ Element* Element::GetLastElementChild() const
 	return *it;
 }
 
-Element* Element::GetLastChild() const
-{
-	return GetLastElementChild();
-}
-
 Element* Element::GetChild(int index) const
 {
 	int i_element = 0;
@@ -1174,7 +1155,7 @@ bool Element::Focus(bool focus_visible)
 
 	// Update the focus chain up the hierarchy.
 	Element* element = this;
-	while (Element* parent = element->GetParentNode())
+	while (Element* parent = element->GetParentElement())
 	{
 		parent->focus = element;
 		element = parent;
@@ -1258,7 +1239,7 @@ void Element::ScrollIntoView(const ScrollIntoViewOptions options)
 	const Vector2f size = main_box.GetSize(BoxArea::Border);
 	ScrollBehavior scroll_behavior = options.behavior;
 
-	for (Element* scroll_parent = GetParentElement(); scroll_parent; scroll_parent = scroll_parent->GetParentNode())
+	for (Element* scroll_parent = GetParentElement(); scroll_parent; scroll_parent = scroll_parent->GetParentElement())
 	{
 		using Style::Overflow;
 		const ComputedValues& computed = scroll_parent->GetComputedValues();
@@ -1448,7 +1429,7 @@ bool Element::Contains(Element* element) const
 	{
 		if (element == this)
 			return true;
-		element = element->GetParentNode();
+		element = element->GetParentElement();
 	}
 	return false;
 }
@@ -1457,7 +1438,7 @@ ElementPtr Element::Remove()
 {
 	if (Node* parent = GetParentNode())
 	{
-		if (NodePtr self = parent->RemoveChild(As<Node*>(this)))
+		if (NodePtr self = parent->RemoveChild(this))
 			return As<ElementPtr>(std::move(self));
 	}
 	return nullptr;
@@ -2303,7 +2284,7 @@ void Element::DirtyStackingContext()
 	Element* stacking_context_parent = this;
 	while (stacking_context_parent && !stacking_context_parent->local_stacking_context)
 	{
-		stacking_context_parent = stacking_context_parent->GetParentNode();
+		stacking_context_parent = stacking_context_parent->GetParentElement();
 	}
 
 	if (stacking_context_parent)

+ 7 - 7
Source/Core/ElementDocument.cpp

@@ -524,8 +524,8 @@ void ElementDocument::UpdateLayout()
 		RMLUI_ZoneText(source_url.c_str(), source_url.size());
 
 		Vector2f containing_block(0, 0);
-		if (GetParentNode() != nullptr)
-			containing_block = GetParentNode()->GetBox().GetSize();
+		if (Element* parent = GetParentElement())
+			containing_block = parent->GetBox().GetSize();
 
 		LayoutEngine::FormatElement(this, containing_block);
 
@@ -543,7 +543,7 @@ void ElementDocument::UpdatePosition()
 
 		position_dirty = false;
 
-		Element* root = GetParentNode();
+		Element* root = GetParentElement();
 
 		// We only position ourselves if we are a child of our context's root element. That is, we don't want to proceed
 		// if we are unparented or an iframe document.
@@ -663,7 +663,7 @@ void ElementDocument::ProcessDefaultAction(Event& event)
 				{
 					if (CanFocusElement(focus_node) == CanFocus::Yes)
 						break;
-					focus_node = focus_node->GetParentNode();
+					focus_node = focus_node->GetParentElement();
 				}
 				return focus_node ? focus_node : this;
 			};
@@ -729,7 +729,7 @@ Element* ElementDocument::FindNextTabElement(Element* current_element, bool forw
 	bool search_enabled = false;
 	Element* document = current_element->GetOwnerDocument();
 	Element* child = current_element;
-	Element* parent = current_element->GetParentNode();
+	Element* parent = current_element->GetParentElement();
 	while (child != document)
 	{
 		const int num_children = parent->GetNumChildren();
@@ -751,7 +751,7 @@ Element* ElementDocument::FindNextTabElement(Element* current_element, bool forw
 
 		// Advance up the tree
 		child = parent;
-		parent = parent->GetParentNode();
+		parent = parent->GetParentElement();
 		search_enabled = false;
 	}
 
@@ -851,7 +851,7 @@ Element* ElementDocument::FindNextNavigationElement(Element* current_element, Na
 	const BoundingBox bounding_box = {position, position + current_element->GetBox().GetSize(BoxArea::Border)};
 
 	auto GetNearestScrollContainer = [this](Element* element) -> Element* {
-		for (element = element->GetParentNode(); element; element = element->GetParentNode())
+		for (element = element->GetParentElement(); element; element = element->GetParentElement())
 		{
 			if (IsScrollContainer(element))
 				return element;

+ 1 - 1
Source/Core/ElementHandle.cpp

@@ -205,7 +205,7 @@ private:
 	}
 	Vector2f DistanceToBottomRight(Vector2f distance_to_top_left) const
 	{
-		const Vector2f scroll_size = {target->GetParentNode()->GetScrollWidth(), target->GetParentNode()->GetScrollHeight()};
+		const Vector2f scroll_size = {target->GetParentElement()->GetScrollWidth(), target->GetParentElement()->GetScrollHeight()};
 		return scroll_size - box.GetSize(BoxArea::Border) - distance_to_top_left;
 	}
 

+ 4 - 5
Source/Core/ElementScroll.cpp

@@ -225,9 +225,8 @@ bool ElementScroll::CreateScrollbar(Orientation orientation)
 	scrollbars[orientation].widget = MakeUnique<WidgetScroll>(scrollbars[orientation].element);
 	scrollbars[orientation].widget->Initialise(orientation == VERTICAL ? WidgetScroll::VERTICAL : WidgetScroll::HORIZONTAL);
 
-	Element* child = element->AppendChild(std::move(scrollbar_element), false);
-
-	UpdateScrollElementProperties(child);
+	element->AppendChild(std::move(scrollbar_element), false);
+	UpdateScrollElementProperties(scrollbars[orientation].element);
 
 	return true;
 }
@@ -242,8 +241,8 @@ bool ElementScroll::CreateCorner()
 	corner->SetProperty(PropertyId::Clip, Property(1, Unit::NUMBER));
 	corner->SetProperty(PropertyId::Drag, Property(Style::Drag::Block));
 
-	Element* child = element->AppendChild(std::move(corner_element), false);
-	UpdateScrollElementProperties(child);
+	element->AppendChild(std::move(corner_element), false);
+	UpdateScrollElementProperties(corner);
 
 	return true;
 }

+ 3 - 3
Source/Core/ElementStyle.cpp

@@ -93,14 +93,14 @@ const Property* ElementStyle::GetProperty(PropertyId id, const Element* element,
 	// If we can inherit this property, return our parent's property.
 	if (property->IsInherited())
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		while (parent)
 		{
 			const Property* parent_property = parent->GetStyle()->GetLocalProperty(id);
 			if (parent_property)
 				return parent_property;
 
-			parent = parent->GetParentNode();
+			parent = parent->GetParentElement();
 		}
 	}
 
@@ -418,7 +418,7 @@ float ElementStyle::ResolveRelativeLength(NumericValue value, RelativeTarget rel
 	case RelativeTarget::FontSize: base_value = element->GetComputedValues().font_size(); break;
 	case RelativeTarget::ParentFontSize:
 	{
-		auto p = element->GetParentNode();
+		auto p = element->GetParentElement();
 		base_value = (p ? p->GetComputedValues().font_size() : DefaultComputedValues().font_size());
 	}
 	break;

+ 2 - 2
Source/Core/ElementText.cpp

@@ -253,7 +253,7 @@ bool ElementText::GenerateLine(String& line, int& line_length, float& line_width
 	// Bail if we don't have a valid font face.
 	if (font_face_handle == 0)
 	{
-		LogMissingFontFace(GetParentNode() ? GetParentNode() : this);
+		LogMissingFontFace(GetParentElement() ? GetParentElement() : this);
 		return true;
 	}
 
@@ -509,7 +509,7 @@ void ElementText::GenerateGeometry(RenderManager& render_manager, const FontFace
 {
 	RMLUI_ZoneScopedC(0xD2691E);
 
-	const TextOverflowResolved text_overflow = ResolveTextOverflow(GetParentNode(), font_face_handle);
+	const TextOverflowResolved text_overflow = ResolveTextOverflow(GetParentElement(), font_face_handle);
 
 	const auto& computed = GetComputedValues();
 	const TextShapingContext text_shaping_context{computed.language(), computed.direction(), computed.font_kerning(), computed.letter_spacing()};

+ 1 - 1
Source/Core/ElementUtilities.cpp

@@ -356,7 +356,7 @@ void ElementUtilities::BuildBox(Box& box, Vector2f containing_block, Element* el
 
 bool ElementUtilities::PositionElement(Element* element, Vector2f offset, PositionAnchor anchor)
 {
-	Element* parent = element->GetParentNode();
+	Element* parent = element->GetParentElement();
 	if (!parent)
 		return false;
 

+ 2 - 2
Source/Core/Elements/ElementFormControlSelect.cpp

@@ -165,9 +165,9 @@ void ElementFormControlSelect::OnChildRemove(Element* child)
 void ElementFormControlSelect::MoveChildren()
 {
 	// Move any child elements into the widget (except for the three functional elements).
-	while (Element* raw_child = GetFirstChild())
+	while (Element* raw_child = GetFirstElementChild())
 	{
-		ElementPtr child = RemoveChild(raw_child);
+		ElementPtr child = As<ElementPtr>(RemoveChild(raw_child));
 		widget->AddOption(std::move(child), -1);
 	}
 }

+ 3 - 3
Source/Core/Elements/ElementProgress.cpp

@@ -49,9 +49,9 @@ ElementProgress::ElementProgress(const String& tag) :
 	geometry_dirty = false;
 
 	// Add the fill element as a non-DOM element.
-	ElementPtr fill_element = As<ElementPtr>(Factory::InstanceNode("*", "fill"));
-	RMLUI_ASSERT(fill_element);
-	fill = AppendChild(std::move(fill_element), false);
+	NodePtr fill_node = Factory::InstanceNode("*", "fill");
+	RMLUI_ASSERT(fill_node);
+	fill = As<Element*>(AppendChild(std::move(fill_node), false));
 }
 
 ElementProgress::~ElementProgress() {}

+ 8 - 8
Source/Core/Elements/ElementTabSet.cpp

@@ -146,8 +146,8 @@ void ElementTabSet::ProcessDefaultAction(Event& event)
 		// Find the tab that this click occured on
 		Element* tabs = GetChildByTag("tabs");
 		Element* tab = event.GetTargetElement();
-		while (tab && tab != this && tab->GetParentNode() != tabs)
-			tab = tab->GetParentNode();
+		while (tab && tab != this && tab->GetParentElement() != tabs)
+			tab = tab->GetParentElement();
 
 		// Abort if we couldn't find the tab the click occured on
 		if (!tab || tab == this)
@@ -172,22 +172,22 @@ void ElementTabSet::OnChildAdd(Element* child)
 {
 	Element::OnChildAdd(child);
 
-	if (child->GetParentNode() == GetChildByTag("tabs"))
+	if (child->GetParentElement() == GetChildByTag("tabs"))
 	{
 		// Set up the new button and append it
 		child->RemoveProperty(PropertyId::Display);
 
-		if (child->GetParentNode()->GetChild(active_tab) == child)
+		if (child->GetParentElement()->GetChild(active_tab) == child)
 			child->SetPseudoClass("selected", true);
 	}
 
-	if (child->GetParentNode() == GetChildByTag("panels"))
+	if (child->GetParentElement() == GetChildByTag("panels"))
 	{
 		// Hide the new tab window
 		child->SetProperty(PropertyId::Display, Property(Style::Display::None));
 
 		// Make the new element visible if its the active tab
-		if (child->GetParentNode()->GetChild(active_tab) == child)
+		if (child->GetParentElement()->GetChild(active_tab) == child)
 		{
 			child->SetPseudoClass("selected", true);
 			child->RemoveProperty(PropertyId::Display);
@@ -205,8 +205,8 @@ Element* ElementTabSet::GetChildByTag(const String& tag)
 	}
 
 	// If it doesn't exist, create it
-	ElementPtr element = As<ElementPtr>(Factory::InstanceNode("*", tag));
-	Element* result = AppendChild(std::move(element));
+	NodePtr node = Factory::InstanceNode("*", tag);
+	Element* result = As<Element*>(AppendChild(std::move(node)));
 	return result;
 }
 

+ 3 - 3
Source/Core/Elements/InputTypeRadio.cpp

@@ -96,11 +96,11 @@ void InputTypeRadio::PopRadioSet()
 {
 	// Uncheck all other radio buttons with our name in the form.
 	String stop_tag;
-	Element* parent = element->GetParentNode();
+	Element* parent = element->GetParentElement();
 	while (parent != nullptr && rmlui_dynamic_cast<ElementForm*>(parent) == nullptr)
-		parent = parent->GetParentNode();
+		parent = parent->GetParentElement();
 
-	//If no containing form was found, use the containing document as the parent
+	// If no containing form was found, use the containing document as the parent
 	if (parent == nullptr)
 	{
 		parent = element->GetOwnerDocument();

+ 2 - 2
Source/Core/Elements/InputTypeSubmit.cpp

@@ -62,7 +62,7 @@ void InputTypeSubmit::ProcessDefaultAction(Event& event)
 {
 	if (event == EventId::Click && !element->IsDisabled())
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		while (parent)
 		{
 			ElementForm* form = rmlui_dynamic_cast<ElementForm*>(parent);
@@ -73,7 +73,7 @@ void InputTypeSubmit::ProcessDefaultAction(Event& event)
 			}
 			else
 			{
-				parent = parent->GetParentNode();
+				parent = parent->GetParentElement();
 			}
 		}
 	}

+ 10 - 10
Source/Core/Elements/WidgetDropDown.cpp

@@ -47,9 +47,9 @@ WidgetDropDown::WidgetDropDown(ElementFormControl* element)
 	parent_element = element;
 
 	// Create the button and selection elements.
-	button_element = parent_element->AppendChild(As<ElementPtr>(Factory::InstanceNode("*", "selectarrow")), false);
-	value_element = parent_element->AppendChild(As<ElementPtr>(Factory::InstanceNode("*", "selectvalue")), false);
-	selection_element = parent_element->AppendChild(As<ElementPtr>(Factory::InstanceNode("*", "selectbox")), false);
+	button_element = As<Element*>(parent_element->AppendChild(Factory::InstanceNode("*", "selectarrow"), false));
+	value_element = As<Element*>(parent_element->AppendChild(Factory::InstanceNode("*", "selectvalue"), false));
+	selection_element = As<Element*>(parent_element->AppendChild(Factory::InstanceNode("*", "selectbox"), false));
 
 	value_element->SetProperty(PropertyId::OverflowX, Property(Style::Overflow::Hidden));
 	value_element->SetProperty(PropertyId::OverflowY, Property(Style::Overflow::Hidden));
@@ -94,7 +94,7 @@ void WidgetDropDown::OnUpdate()
 		//  3. The first option.
 		// The select element's value may change as a result of this.
 		const String select_value = parent_element->GetAttribute("value", String());
-		Element* select_option = selection_element->GetFirstChild();
+		Element* select_option = selection_element->GetFirstElementChild();
 
 		const int num_options = selection_element->GetNumChildren();
 		for (int i = 0; i < num_options; i++)
@@ -431,7 +431,7 @@ void WidgetDropDown::RemoveOption(int index)
 
 void WidgetDropDown::ClearOptions()
 {
-	while (Element* element = selection_element->GetLastChild())
+	while (Element* element = selection_element->GetLastElementChild())
 		selection_element->RemoveChild(element);
 }
 
@@ -448,7 +448,7 @@ int WidgetDropDown::GetNumOptions() const
 void WidgetDropDown::OnChildAdd(Element* element)
 {
 	// We have a special case for 'data-for' here, since that element must remain hidden.
-	if (element->GetParentNode() != selection_element || element->HasAttribute("data-for") || element->GetTagName() != "option")
+	if (element->GetParentElement() != selection_element || element->HasAttribute("data-for") || element->GetTagName() != "option")
 		return;
 
 	// Force to block display. Register a click handler so we can be notified of selection.
@@ -466,7 +466,7 @@ void WidgetDropDown::OnChildAdd(Element* element)
 
 void WidgetDropDown::OnChildRemove(Element* element)
 {
-	if (element->GetParentNode() != selection_element)
+	if (element->GetParentElement() != selection_element)
 		return;
 
 	element->RemoveEventListener(EventId::Click, this);
@@ -500,7 +500,7 @@ void WidgetDropDown::ProcessEvent(Event& event)
 	{
 	case EventId::Click:
 	{
-		if (event.GetCurrentElement()->GetParentNode() == selection_element)
+		if (event.GetCurrentElement()->GetParentElement() == selection_element)
 		{
 			const int num_options = selection_element->GetNumChildren();
 			// Find the element in the options and fire the selection event
@@ -531,7 +531,7 @@ void WidgetDropDown::ProcessEvent(Event& event)
 			{
 				if (element == selection_element)
 					return;
-				element = element->GetParentNode();
+				element = element->GetParentElement();
 			}
 
 			if (selection_element->GetComputedValues().visibility() == Style::Visibility::Hidden)
@@ -606,7 +606,7 @@ void WidgetDropDown::ProcessEvent(Event& event)
 			// Close the select box if we scroll outside the select box.
 			bool scrolls_selection_box = false;
 
-			for (Element* element = event.GetTargetElement(); element; element = element->GetParentNode())
+			for (Element* element = event.GetTargetElement(); element; element = element->GetParentElement())
 			{
 				if (element == selection_element)
 				{

+ 5 - 16
Source/Core/Elements/WidgetSlider.cpp

@@ -94,22 +94,11 @@ WidgetSlider::~WidgetSlider()
 
 bool WidgetSlider::Initialise()
 {
-	// Create all of our child elements as standard elements, and abort if we can't create them.
-	ElementPtr track_element = As<ElementPtr>(Factory::InstanceNode("*", "slidertrack"));
-	ElementPtr bar_element = As<ElementPtr>(Factory::InstanceNode("*", "sliderbar"));
-	ElementPtr progress_element = As<ElementPtr>(Factory::InstanceNode("*", "sliderprogress"));
-	ElementPtr arrow0_element = As<ElementPtr>(Factory::InstanceNode("*", "sliderarrowdec"));
-	ElementPtr arrow1_element = As<ElementPtr>(Factory::InstanceNode("*", "sliderarrowinc"));
-
-	if (!track_element || !bar_element || !progress_element || !arrow0_element || !arrow1_element)
-		return false;
-
-	// Add them as non-DOM elements.
-	track = parent->AppendChild(std::move(track_element), false);
-	progress = track->AppendChild(std::move(progress_element), false);
-	bar = parent->AppendChild(std::move(bar_element), false);
-	arrows[0] = parent->AppendChild(std::move(arrow0_element), false);
-	arrows[1] = parent->AppendChild(std::move(arrow1_element), false);
+	track = As<Element*>(parent->AppendChild(Factory::InstanceNode("*", "slidertrack"), false));
+	progress = As<Element*>(track->AppendChild(Factory::InstanceNode("*", "sliderprogress"), false));
+	bar = As<Element*>(parent->AppendChild(Factory::InstanceNode("*", "sliderbar"), false));
+	arrows[0] = As<Element*>(parent->AppendChild(Factory::InstanceNode("*", "sliderarrowdec"), false));
+	arrows[1] = As<Element*>(parent->AppendChild(Factory::InstanceNode("*", "sliderarrowinc"), false));
 
 	const Property drag_property = Property(Style::Drag::Drag);
 	track->SetProperty(PropertyId::Drag, drag_property);

+ 1 - 1
Source/Core/Elements/XMLNodeHandlerTextArea.cpp

@@ -47,7 +47,7 @@ Element* XMLNodeHandlerTextArea::ElementStart(XMLParser* parser, const String& n
 		ElementPtr new_element = As<ElementPtr>(Factory::InstanceNode(name, name));
 		new_element->SetAttributes(attributes);
 
-		Element* result = parser->GetParseFrame()->element->AppendChild(std::move(new_element));
+		Element* result = As<Element*>(parser->GetParseFrame()->element->AppendChild(std::move(new_element)));
 		return result;
 	}
 

+ 1 - 1
Source/Core/EventDispatcher.cpp

@@ -155,7 +155,7 @@ bool EventDispatcher::DispatchEvent(Element* target_element, const EventId id, c
 			default_action_elements.push_back(walk_element->GetObserverPtr());
 		}
 
-		walk_element = walk_element->GetParentNode();
+		walk_element = walk_element->GetParentElement();
 		dom_distance_from_target += 1;
 	}
 

+ 1 - 1
Source/Core/Layout/FormattingContext.cpp

@@ -61,7 +61,7 @@ UniquePtr<LayoutBox> FormattingContext::FormatIndependent(ContainerBox* parent_c
 	}
 	else if (display == Display::InlineBlock || display == Display::FlowRoot || display == Display::TableCell || computed.float_() != Float::None ||
 		computed.position() == Position::Absolute || computed.position() == Position::Fixed || computed.overflow_x() != Overflow::Visible ||
-		computed.overflow_y() != Overflow::Visible || !element->GetParentNode() || element->GetParentNode()->GetDisplay() == Display::Flex)
+		computed.overflow_y() != Overflow::Visible || !element->GetParentElement() || element->GetParentElement()->GetDisplay() == Display::Flex)
 	{
 		type = FormattingContextType::Block;
 	}

+ 56 - 25
Source/Core/Node.cpp

@@ -35,6 +35,37 @@
 
 namespace Rml {
 
+static int NodeIndexInParent(const Node* node)
+{
+	const Node* parent = node->GetParentNode();
+	if (!parent)
+		return -1;
+
+	int index = 0;
+	for (const Node* sibling : parent->IterateChildren<Node>())
+	{
+		if (sibling == node)
+			return index;
+		index++;
+	}
+	return -1;
+}
+
+NodePtrProxy::NodePtrProxy(NodePtr node) : node(std::move(node)) {}
+NodePtrProxy::NodePtrProxy(ElementPtr element) : node(As<NodePtr>(std::move(element))) {}
+Node* NodePtrProxy::Get()
+{
+	return node.get();
+}
+NodePtr NodePtrProxy::Extract()
+{
+	return std::move(node);
+}
+NodePtrProxy::operator bool() const
+{
+	return node != nullptr;
+}
+
 Node::Node() {}
 
 Node::~Node()
@@ -67,18 +98,18 @@ bool Node::HasChildNodes() const
 	return (int)children.size() > num_non_dom_children;
 }
 
-Node* Node::AppendChild(NodePtr child, bool dom_node)
+Node* Node::AppendChild(NodePtrProxy child, bool dom_node)
 {
-	RMLUI_ASSERT(child && child.get() != this);
-	Node* child_ptr = child.get();
+	RMLUI_ASSERT(child && child.Get() != this);
+	Node* child_ptr = child.Get();
 	if (dom_node)
 	{
 		auto it_end = children.end();
-		children.insert(it_end - num_non_dom_children, std::move(child));
+		children.insert(it_end - num_non_dom_children, child.Extract());
 	}
 	else
 	{
-		children.push_back(std::move(child));
+		children.push_back(child.Extract());
 		num_non_dom_children++;
 	}
 	// Set parent just after inserting into children. This allows us to e.g. get our previous sibling in SetParent.
@@ -89,7 +120,7 @@ Node* Node::AppendChild(NodePtr child, bool dom_node)
 	return child_ptr;
 }
 
-Node* Node::InsertBefore(NodePtr child, Node* adjacent_node)
+Node* Node::InsertBefore(NodePtrProxy child, Node* adjacent_node)
 {
 	RMLUI_ASSERT(child);
 	// Find the position in the list of children of the adjacent element. If it's nullptr, or we can't find it, then we
@@ -112,40 +143,40 @@ Node* Node::InsertBefore(NodePtr child, Node* adjacent_node)
 
 	if (found_child)
 	{
-		child_ptr = child.get();
+		child_ptr = child.Get();
 
 		const bool dom_node = ((int)child_index < GetNumChildNodes());
 		if (!dom_node)
 			num_non_dom_children++;
 
-		children.insert(children.begin() + child_index, std::move(child));
+		children.insert(children.begin() + child_index, child.Extract());
 		child_ptr->SetParent(this);
 
 		OnChildNodeAdd(child_ptr, dom_node);
 	}
 	else
 	{
-		child_ptr = AppendChild(std::move(child));
+		child_ptr = AppendChild(child.Extract());
 	}
 
 	return child_ptr;
 }
 
-NodePtr Node::ReplaceChild(NodePtr insert_node, Node* replace_node)
+NodePtr Node::ReplaceChild(NodePtrProxy insert_node, Node* replace_node)
 {
 	RMLUI_ASSERT(insert_node);
 	auto it_replace = std::find_if(children.begin(), children.end(), [replace_node](const NodePtr& node) { return node.get() == replace_node; });
 	if (it_replace == children.end())
 	{
-		AppendChild(std::move(insert_node));
+		AppendChild(insert_node.Extract());
 		return nullptr;
 	}
 
 	const std::ptrdiff_t replace_index = std::distance(children.begin(), it_replace);
 	const bool dom_node = (replace_index < (std::ptrdiff_t)children.size() - num_non_dom_children);
 
-	Node* inserted_node_ptr = insert_node.get();
-	children.insert(children.begin() + replace_index, std::move(insert_node));
+	Node* inserted_node_ptr = insert_node.Get();
+	children.insert(children.begin() + replace_index, insert_node.Extract());
 	if (!dom_node)
 		num_non_dom_children++;
 	inserted_node_ptr->SetParent(this);
@@ -178,34 +209,34 @@ NodePtr Node::RemoveChild(Node* child)
 	return detached_child;
 }
 
-Element* Node::AppendChild(ElementPtr child, bool dom_element)
+Element* Node::GetParentElement() const
 {
-	return rmlui_static_cast<Element*>(AppendChild(As<NodePtr>(std::move(child)), dom_element));
+	return AsIf<Element*>(GetParentNode());
 }
 
-Element* Node::InsertBefore(ElementPtr child, Element* adjacent_element)
+Node* Node::GetParentNode() const
 {
-	return rmlui_static_cast<Element*>(InsertBefore(As<NodePtr>(std::move(child)), adjacent_element));
+	return parent;
 }
 
-ElementPtr Node::ReplaceChild(ElementPtr inserted_element, Element* replaced_element)
+Node* Node::GetNextSibling() const
 {
-	return As<ElementPtr>(ReplaceChild(As<NodePtr>(std::move(inserted_element)), replaced_element));
+	return GetChildNode(NodeIndexInParent(this) + 1);
 }
 
-ElementPtr Node::RemoveChild(Element* child)
+Node* Node::GetPreviousSibling() const
 {
-	return As<ElementPtr>(RemoveChild(As<Node*>(child)));
+	return GetChildNode(NodeIndexInParent(this) - 1);
 }
 
-Element* Node::GetParentNode() const
+Node* Node::GetFirstChild() const
 {
-	return GetParentElement();
+	return children.empty() ? nullptr : children.front().get();
 }
 
-Element* Node::GetParentElement() const
+Node* Node::GetLastChild() const
 {
-	return rmlui_dynamic_cast<Element*>(parent);
+	return children.empty() ? nullptr : children.back().get();
 }
 
 ElementDocument* Node::GetOwnerDocument() const

+ 2 - 2
Source/Core/StyleSheetNode.cpp

@@ -305,7 +305,7 @@ bool StyleSheetNode::TraverseMatch(const Element* element, const Element* scope)
 	{
 		// Try to match the next element parent. If it succeeds we continue on to the next node, otherwise we try an alternate path through the
 		// hierarchy using the next element parent. Repeat until we run out of elements.
-		for (element = element->GetParentNode(); element; element = element->GetParentNode())
+		for (element = element->GetParentElement(); element; element = element->GetParentElement())
 		{
 			if (parent->Match(element, scope) && parent->TraverseMatch(element, scope))
 				return true;
@@ -318,7 +318,7 @@ bool StyleSheetNode::TraverseMatch(const Element* element, const Element* scope)
 	case SelectorCombinator::NextSibling:
 	case SelectorCombinator::SubsequentSibling:
 	{
-		Element* parent_element = element->GetParentNode();
+		Element* parent_element = element->GetParentElement();
 		if (!parent_element)
 			return false;
 

+ 10 - 10
Source/Core/StyleSheetSelector.cpp

@@ -98,7 +98,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	{
 	case StructuralSelectorType::Nth_Child:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 
@@ -124,7 +124,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	break;
 	case StructuralSelectorType::Nth_Last_Child:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 
@@ -150,7 +150,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	break;
 	case StructuralSelectorType::Nth_Of_Type:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 
@@ -177,7 +177,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	break;
 	case StructuralSelectorType::Nth_Last_Of_Type:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 
@@ -203,7 +203,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	break;
 	case StructuralSelectorType::First_Child:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 
@@ -228,7 +228,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	break;
 	case StructuralSelectorType::Last_Child:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 
@@ -253,7 +253,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	break;
 	case StructuralSelectorType::First_Of_Type:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 
@@ -277,7 +277,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	break;
 	case StructuralSelectorType::Last_Of_Type:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 
@@ -301,7 +301,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	break;
 	case StructuralSelectorType::Only_Child:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 
@@ -326,7 +326,7 @@ bool IsSelectorApplicable(const Element* element, const StructuralSelector& sele
 	break;
 	case StructuralSelectorType::Only_Of_Type:
 	{
-		Element* parent = element->GetParentNode();
+		Element* parent = element->GetParentElement();
 		if (!parent)
 			return false;
 

+ 5 - 17
Source/Core/WidgetScroll.cpp

@@ -108,22 +108,10 @@ bool WidgetScroll::Initialise(Orientation _orientation)
 
 	orientation = _orientation;
 
-	// Create all of our child elements as standard elements, and abort if we can't create them.
-	ElementPtr track_element = As<ElementPtr>(Factory::InstanceNode("*", "slidertrack"));
-	ElementPtr bar_element = As<ElementPtr>(Factory::InstanceNode("*", "sliderbar"));
-	ElementPtr arrow0_element = As<ElementPtr>(Factory::InstanceNode("*", "sliderarrowdec"));
-	ElementPtr arrow1_element = As<ElementPtr>(Factory::InstanceNode("*", "sliderarrowinc"));
-
-	if (!track_element || !bar_element || !arrow0_element || !arrow1_element)
-	{
-		return false;
-	}
-
-	// Add them as non-DOM elements.
-	track = parent->AppendChild(std::move(track_element), false);
-	bar = parent->AppendChild(std::move(bar_element), false);
-	arrows[0] = parent->AppendChild(std::move(arrow0_element), false);
-	arrows[1] = parent->AppendChild(std::move(arrow1_element), false);
+	track = As<Element*>(parent->AppendChild(Factory::InstanceNode("*", "slidertrack"), false));
+	bar = As<Element*>(parent->AppendChild(Factory::InstanceNode("*", "sliderbar"), false));
+	arrows[0] = As<Element*>(parent->AppendChild(Factory::InstanceNode("*", "sliderarrowdec"), false));
+	arrows[1] = As<Element*>(parent->AppendChild(Factory::InstanceNode("*", "sliderarrowinc"), false));
 
 	bar->SetProperty(PropertyId::Drag, Property(Style::Drag::Drag));
 
@@ -513,7 +501,7 @@ void WidgetScroll::Scroll(float distance, ScrollBehavior behavior)
 		new_bar_position = Math::Clamp((bar_position * traversable_track_length + distance) / traversable_track_length, 0.f, 1.f);
 
 	// 'parent' is the scrollbar element, its parent again is the actual element we want to scroll
-	Element* element_scroll = parent->GetParentNode();
+	Element* element_scroll = parent->GetParentElement();
 	if (!element_scroll)
 	{
 		RMLUI_ERROR;

+ 1 - 1
Source/Core/XMLNodeHandlerDefault.cpp

@@ -53,7 +53,7 @@ Element* XMLNodeHandlerDefault::ElementStart(XMLParser* parser, const String& na
 	element->SetAttributes(attributes);
 
 	// Move and append the element to the parent
-	Element* result = parent->AppendChild(std::move(element));
+	Element* result = As<Element*>(parent->AppendChild(std::move(element)));
 
 	return result;
 }

+ 10 - 10
Source/Debugger/ElementInfo.cpp

@@ -267,7 +267,7 @@ void ElementInfo::ProcessEvent(Event& event)
 						for (int i = 0; i < element_index; i++)
 						{
 							if (new_source_element != nullptr)
-								new_source_element = new_source_element->GetParentNode();
+								new_source_element = new_source_element->GetParentElement();
 						}
 						SetSourceElement(new_source_element);
 					}
@@ -305,7 +305,7 @@ void ElementInfo::ProcessEvent(Event& event)
 					for (int i = 0; i < element_index; i++)
 					{
 						if (hover_element != nullptr)
-							hover_element = hover_element->GetParentNode();
+							hover_element = hover_element->GetParentElement();
 					}
 				}
 				else if (sscanf(id.c_str(), "c %d", &element_index) == 1)
@@ -422,7 +422,7 @@ void ElementInfo::UpdateSourceElement()
 				// Finally, create new pseudo buttons for the rest of the active pseudo classes.
 				for (auto& extra_pseudo : list)
 				{
-					Element* grandchild = child->AppendChild(CreateElement("pseudo"));
+					Element* grandchild = As<Element*>(child->AppendChild(CreateElement("pseudo")));
 					grandchild->SetClass("active", true);
 					grandchild->SetAttribute("name", extra_pseudo);
 					grandchild->SetInnerRML(":" + extra_pseudo);
@@ -478,7 +478,7 @@ void ElementInfo::UpdateSourceElement()
 		if (attributes.empty())
 		{
 			while (attributes_content->HasChildNodes())
-				attributes_content->RemoveChild(attributes_content->GetChild(0));
+				attributes_content->RemoveChild(attributes_content->GetFirstChild());
 			attributes_rml.clear();
 		}
 		else if (attributes != attributes_rml)
@@ -515,7 +515,7 @@ void ElementInfo::UpdateSourceElement()
 		if (events.empty())
 		{
 			while (events_content->HasChildNodes())
-				events_content->RemoveChild(events_content->GetChild(0));
+				events_content->RemoveChild(events_content->GetFirstChild());
 			events_rml.clear();
 		}
 		else if (events != events_rml)
@@ -573,14 +573,14 @@ void ElementInfo::UpdateSourceElement()
 		String ancestors;
 		Element* element_ancestor = nullptr;
 		if (source_element != nullptr)
-			element_ancestor = source_element->GetParentNode();
+			element_ancestor = source_element->GetParentElement();
 
 		int ancestor_depth = 1;
 		while (element_ancestor)
 		{
 			String ancestor_name = element_ancestor->GetAddress(false, false);
 			ancestors += CreateString("<p id=\"a %d\">%s</p>", ancestor_depth, ancestor_name.c_str());
-			element_ancestor = element_ancestor->GetParentNode();
+			element_ancestor = element_ancestor->GetParentElement();
 			ancestor_depth++;
 		}
 
@@ -627,7 +627,7 @@ void ElementInfo::UpdateSourceElement()
 		if (children.empty())
 		{
 			while (children_content->HasChildNodes())
-				children_content->RemoveChild(children_content->GetChild(0));
+				children_content->RemoveChild(children_content->GetFirstChild());
 			children_rml.clear();
 		}
 		else if (children != children_rml)
@@ -710,8 +710,8 @@ void ElementInfo::BuildElementPropertiesRML(String& property_rml, Element* eleme
 		}
 	}
 
-	if (element->GetParentNode() != nullptr)
-		BuildElementPropertiesRML(property_rml, element->GetParentNode(), primary_element);
+	if (Element* parent = element->GetParentElement())
+		BuildElementPropertiesRML(property_rml, parent, primary_element);
 }
 
 void ElementInfo::BuildPropertyRML(String& property_rml, const String& name, const Property* property)

+ 15 - 12
Source/Debugger/ElementLog.cpp

@@ -82,11 +82,11 @@ ElementLog::~ElementLog()
 {
 	RemoveEventListener(EventId::Click, this);
 
-	if (beacon && beacon->GetFirstChild())
-		beacon->GetFirstChild()->RemoveEventListener(EventId::Click, this);
+	if (beacon && beacon->GetFirstElementChild())
+		beacon->GetFirstElementChild()->RemoveEventListener(EventId::Click, this);
 
-	if (beacon && beacon->GetParentNode())
-		beacon->GetParentNode()->RemoveChild(beacon);
+	if (beacon && beacon->GetParentElement())
+		beacon->GetParentElement()->RemoveChild(beacon);
 
 	if (message_content)
 	{
@@ -123,9 +123,9 @@ bool ElementLog::Initialise()
 	beacon->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden));
 	beacon->SetInnerRML(beacon_rml);
 
-	Element* button = beacon->GetFirstChild();
+	Element* button = beacon->GetFirstElementChild();
 	if (button)
-		beacon->GetFirstChild()->AddEventListener(EventId::Click, this);
+		beacon->GetFirstElementChild()->AddEventListener(EventId::Click, this);
 
 	style_sheet = Factory::InstanceStyleSheetString(String(common_rcss) + String(beacon_rcss));
 	if (!style_sheet)
@@ -177,7 +177,7 @@ void ElementLog::AddLogMessage(Log::Type type, const String& message)
 				beacon->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible));
 
 				current_beacon_level = type;
-				Element* beacon_button = beacon->GetFirstChild();
+				Element* beacon_button = beacon->GetFirstElementChild();
 				if (beacon_button)
 				{
 					beacon_button->SetClassNames(log_types[type].class_name);
@@ -221,9 +221,9 @@ void ElementLog::OnUpdate()
 				num_messages++;
 			}
 
-			if (message_content->HasChildNodes())
+			if (Element* last_element = message_content->GetLastElementChild())
 			{
-				float last_element_top = message_content->GetLastChild()->GetAbsoluteTop();
+				const float last_element_top = last_element->GetAbsoluteTop();
 				auto_scroll = message_content->GetAbsoluteTop() + message_content->GetAbsoluteTop() > last_element_top;
 			}
 			else
@@ -243,7 +243,7 @@ void ElementLog::ProcessEvent(Event& event)
 	{
 		if (event == EventId::Click)
 		{
-			if (event.GetTargetElement() == beacon->GetFirstChild())
+			if (event.GetTargetElement() == beacon->GetFirstElementChild())
 			{
 				if (!IsVisible())
 					SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible));
@@ -288,8 +288,11 @@ void ElementLog::ProcessEvent(Event& event)
 
 	if (event == EventId::Resize && auto_scroll)
 	{
-		if (message_content != nullptr && message_content->HasChildNodes())
-			message_content->GetLastChild()->ScrollIntoView();
+		if (message_content)
+		{
+			if (Element* child = message_content->GetLastElementChild())
+				child->ScrollIntoView();
+		}
 	}
 }
 

+ 7 - 7
Source/Lua/Element.cpp

@@ -102,7 +102,7 @@ int ElementAppendChild(lua_State* L, Element* obj)
 	ElementPtr* element = LuaType<ElementPtr>::check(L, 1);
 	if (*element)
 	{
-		Element* child = obj->AppendChild(std::move(*element));
+		Element* child = As<Element*>(obj->AppendChild(std::move(*element)));
 		LuaType<Element>::push(L, child, false);
 	}
 	else
@@ -237,7 +237,7 @@ int ElementInsertBefore(lua_State* L, Element* obj)
 	Element* adjacent = LuaType<Element>::check(L, 2);
 	if (*element)
 	{
-		Element* inserted = obj->InsertBefore(std::move(*element), adjacent);
+		Element* inserted = As<Element*>(obj->InsertBefore(std::move(*element), adjacent));
 		LuaType<Element>::push(L, inserted, false);
 	}
 	else
@@ -371,7 +371,7 @@ int ElementGetAttrfirst_child(lua_State* L)
 {
 	Element* ele = LuaType<Element>::check(L, 1);
 	RMLUI_CHECK_OBJ(ele);
-	Element* child = ele->GetFirstChild();
+	Element* child = ele->GetFirstElementChild();
 	if (child == nullptr)
 		lua_pushnil(L);
 	else
@@ -399,7 +399,7 @@ int ElementGetAttrlast_child(lua_State* L)
 {
 	Element* ele = LuaType<Element>::check(L, 1);
 	RMLUI_CHECK_OBJ(ele);
-	Element* child = ele->GetLastChild();
+	Element* child = ele->GetLastElementChild();
 	if (child == nullptr)
 		lua_pushnil(L);
 	else
@@ -411,7 +411,7 @@ int ElementGetAttrnext_sibling(lua_State* L)
 {
 	Element* ele = LuaType<Element>::check(L, 1);
 	RMLUI_CHECK_OBJ(ele);
-	Element* sibling = ele->GetNextSibling();
+	Element* sibling = ele->GetNextElementSibling();
 	if (sibling == nullptr)
 		lua_pushnil(L);
 	else
@@ -473,7 +473,7 @@ int ElementGetAttrparent_node(lua_State* L)
 {
 	Element* ele = LuaType<Element>::check(L, 1);
 	RMLUI_CHECK_OBJ(ele);
-	Element* parent = ele->GetParentNode();
+	Element* parent = ele->GetParentElement();
 	if (parent == nullptr)
 		lua_pushnil(L);
 	else
@@ -485,7 +485,7 @@ int ElementGetAttrprevious_sibling(lua_State* L)
 {
 	Element* ele = LuaType<Element>::check(L, 1);
 	RMLUI_CHECK_OBJ(ele);
-	Element* sibling = ele->GetPreviousSibling();
+	Element* sibling = ele->GetPreviousElementSibling();
 	if (sibling == nullptr)
 		lua_pushnil(L);
 	else

+ 2 - 2
Tests/Source/UnitTests/Core.cpp

@@ -176,7 +176,7 @@ TEST_CASE("core.load_texture_only_when_visible")
 	REQUIRE(context);
 
 	ElementDocument* document = context->LoadDocumentFromMemory(document_textures_rml);
-	Element* child_div = document->GetFirstChild();
+	Element* child_div = document->GetFirstElementChild();
 
 	SUBCASE("Invisible")
 	{
@@ -232,7 +232,7 @@ TEST_CASE("core.warn_missing_texture_once_when_visible")
 
 	const String document_missing_textures_rml = StringUtilities::Replace(document_textures_rml, ".tga", "_invalid.tga");
 	ElementDocument* document = context->LoadDocumentFromMemory(document_missing_textures_rml);
-	Element* child_div = document->GetFirstChild();
+	Element* child_div = document->GetFirstElementChild();
 
 	TestsShell::SetNumExpectedWarnings(0);
 	document->Show();

+ 2 - 2
Tests/Source/UnitTests/DataBinding.cpp

@@ -779,12 +779,12 @@ TEST_CASE("data_binding.data_model_on_body")
 	CHECK(document->GetElementById("array_size")->GetInnerRML() == Rml::ToString(array.size()));
 	CHECK(document->GetElementById("array_empty")->GetAttribute<bool>("empty", true) == array.empty());
 
-	Element* element = document->GetElementById("array_empty")->GetNextSibling();
+	Element* element = document->GetElementById("array_empty")->GetNextElementSibling();
 	size_t i = 0;
 	for (; i < array.size() && element; ++i)
 	{
 		CHECK(element->GetInnerRML() == Rml::CreateString("%zu: %d", i, array[i]));
-		element = element->GetNextSibling();
+		element = element->GetNextElementSibling();
 	}
 	CHECK(i == array.size());
 

+ 10 - 9
Tests/Source/UnitTests/Element.cpp

@@ -166,7 +166,7 @@ TEST_CASE("Element")
 	context->Update();
 	context->Render();
 
-	Element* div = document->GetFirstChild();
+	Element* div = document->GetFirstElementChild();
 	Element* span = div->GetChild(1);
 	REQUIRE(div);
 	REQUIRE(div->GetTagName() == "div");
@@ -175,7 +175,7 @@ TEST_CASE("Element")
 
 	SUBCASE("Attribute")
 	{
-		auto* button = document->AppendChild(document->CreateElement("button"));
+		Element* button = As<Element*>(document->AppendChild(document->CreateElement("button")));
 		SUBCASE("Event listener")
 		{
 			namespace tl = trompeloeil;
@@ -194,8 +194,8 @@ TEST_CASE("Element")
 			MockEventListenerInstancer mockEventListenerInstancer;
 			const auto configureMockEventListenerInstancer = [&](const auto value) {
 				expectations.emplace_back(NAMED_REQUIRE_CALL(mockEventListenerInstancer, InstanceEventListener(value, button))
-											  .LR_SIDE_EFFECT(configureMockEventListener())
-											  .LR_RETURN(mockEventListener.get()));
+						.LR_SIDE_EFFECT(configureMockEventListener())
+						.LR_RETURN(mockEventListener.get()));
 			};
 
 			Factory::RegisterEventListenerInstancer(&mockEventListenerInstancer);
@@ -262,7 +262,7 @@ TEST_CASE("Element")
 
 	SUBCASE("CloneManual")
 	{
-		Element* element = document->GetFirstChild();
+		Element* element = document->GetFirstElementChild();
 		REQUIRE(element->GetProperty<String>("background-color") == "#ff0000");
 		CHECK(element->Clone()->GetProperty<String>("background-color") == "#ff0000");
 
@@ -270,19 +270,19 @@ TEST_CASE("Element")
 		CHECK(element->Clone()->GetProperty<String>("background-color") == "#00ff00");
 
 		element->RemoveProperty("background-color");
-		Element* clone = document->AppendChild(element->Clone());
+		Element* clone = As<Element*>(document->AppendChild(element->Clone()));
 		context->Update();
 		CHECK(clone->GetProperty<String>("background-color") == "#ffffff");
 
 		element->SetClass("blue", true);
-		clone = document->AppendChild(element->Clone());
+		clone = As<Element*>(document->AppendChild(element->Clone()));
 		context->Update();
 		CHECK(clone->GetProperty<String>("background-color") == "#0000ff");
 	}
 
 	SUBCASE("SetInnerRML")
 	{
-		Element* element = document->GetFirstChild();
+		Element* element = document->GetFirstElementChild();
 		CHECK(element->GetInnerRML() == "This is a <span>sample</span>.");
 		element->SetInnerRML("text");
 		CHECK(element->GetInnerRML() == "text");
@@ -332,7 +332,8 @@ TEST_CASE("Element")
 		inner_rml = document->GetInnerRML();
 		CHECK(inner_rml == R"(<div style="background-color: #ff0000;">This is a <img /><span>sample</span>.</div>)");
 
-		div->InsertBefore(document->CreateElement("button"), nullptr)->SetInnerRML("Click me");
+		Element* button = As<Element*>(div->InsertBefore(document->CreateElement("button"), nullptr));
+		button->SetInnerRML("Click me");
 		inner_rml = document->GetInnerRML();
 		CHECK(inner_rml == R"(<div style="background-color: #ff0000;">This is a <img /><span>sample</span>.<button>Click me</button></div>)");
 	}

+ 2 - 2
Tests/Source/UnitTests/ElementImage.cpp

@@ -81,7 +81,7 @@ TEST_CASE("elementimage.dp_ratio")
 		auto clone_ptr = div->Clone();
 
 		context->SetDensityIndependentPixelRatio(4.f);
-		Element* clone_div = document->AppendChild(std::move(clone_ptr));
+		Element* clone_div = As<Element*>(document->AppendChild(std::move(clone_ptr)));
 		Element* clone_img = clone_div->GetChild(0);
 		context->Update();
 
@@ -95,7 +95,7 @@ TEST_CASE("elementimage.dp_ratio")
 		new_img_ptr->SetAttribute("src", "high_scores_alien_1.tga");
 
 		context->SetDensityIndependentPixelRatio(4.0f);
-		Element* new_img = document->AppendChild(std::move(new_img_ptr));
+		Element* new_img = As<Element*>(document->AppendChild(std::move(new_img_ptr)));
 		context->Update();
 
 		CHECK(new_img->GetClientWidth() == 4.f * img_width);

+ 2 - 2
Tests/Source/UnitTests/EventListener.cpp

@@ -84,7 +84,7 @@ public:
 			// Test replacing the current element. Need to be careful with regard to lifetime issues. The event's
 			// current element will be destroyed, so we cannot use it after SetInnerRml(). The library should handle
 			// this case safely internally when propagating the event further.
-			Element* parent = element->GetParentNode();
+			Element* parent = element->GetParentElement();
 			parent->SetInnerRML("<button onclick='confirm_exit' onmouseout='cancel_exit' />");
 			if (Element* child = parent->GetChild(0))
 				child->Focus();
@@ -95,7 +95,7 @@ public:
 		}
 		else if (value == "cancel_exit")
 		{
-			if (Element* parent = element->GetParentNode())
+			if (Element* parent = element->GetParentElement())
 				parent->SetInnerRML("<button id='exit' onclick='exit' />");
 		}
 	}

+ 2 - 2
Tests/Source/UnitTests/Selectors.cpp

@@ -334,7 +334,7 @@ static void RemoveElementsWithIds(ElementDocument* document, const String& remov
 	for (const String& id : remove_id_list)
 	{
 		if (Element* element = document->GetElementById(id))
-			element->GetParentNode()->RemoveChild(element);
+			element->GetParentElement()->RemoveChild(element);
 	}
 }
 static void RemoveClassesFromAllElements(ElementDocument* document, const String& remove_classes)
@@ -354,7 +354,7 @@ static void InsertElementBefore(ElementDocument* document, const String& before_
 	Element* element = document->GetElementById(before_id);
 	ElementPtr new_element = document->CreateElement("p");
 	new_element->SetId("Inserted");
-	element->GetParentNode()->InsertBefore(std::move(new_element), element);
+	element->GetParentElement()->InsertBefore(std::move(new_element), element);
 }
 
 TEST_CASE("Selectors")

+ 1 - 1
Tests/Source/UnitTests/XMLParser.cpp

@@ -137,7 +137,7 @@ TEST_CASE("XMLParser.escaping_tags")
 	TestsShell::RenderLoop();
 
 	CHECK(document->GetNumChildren() == 1);
-	CHECK(document->GetFirstChild()->GetTagName() == "#text");
+	CHECK(document->GetFirstElementChild()->GetTagName() == "#text");
 	// Text-access should yield decoded value, while RML-access should yield encoded value
 	CHECK(static_cast<ElementText*>(document->GetFirstChild())->GetText() == "<p>&lt;span/&gt;</p>");
 	CHECK(document->GetInnerRML() == "&lt;p&gt;&amp;lt;span/&amp;gt;&lt;/p&gt;");