Ver Fonte

Now that we have PropertyIds, we can use a bitset to represent dirty properties, increasing iteration performance.
Re-engineered the property iterators, fixing a bug where pseudo class properties with lower specificity was used, as the same property id could be executed twice in ComputeValues().

Michael Ragazzon há 6 anos atrás
pai
commit
05a24f63d5

+ 4 - 2
Build/cmake/FileList.cmake

@@ -15,6 +15,7 @@ set(Core_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledInstancer.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVertical.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVerticalInstancer.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DirtyPropertyList.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DocumentHeader.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementAnimation.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementBackground.h
@@ -59,6 +60,7 @@ set(Core_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/PluginRegistry.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Pool.h
     ${PROJECT_SOURCE_DIR}/Source/Core/precompiled.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertiesIterator.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserAnimation.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.h
@@ -161,10 +163,10 @@ set(Core_PUB_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/MathTypes.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Platform.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Plugin.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertiesIteratorView.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Property.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertyDefinition.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertyDictionary.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertyIterators.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertyParser.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertySpecification.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ReferenceCountable.h
@@ -288,10 +290,10 @@ set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/Plugin.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PluginRegistry.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/precompiled.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertiesIteratorView.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Property.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyDefinition.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyDictionary.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyIterators.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserAnimation.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.cpp

+ 1 - 1
Include/Rocket/Core/Core.h

@@ -62,10 +62,10 @@
 #include "Input.h"
 #include "Log.h"
 #include "Plugin.h"
+#include "PropertiesIteratorView.h"
 #include "Property.h"
 #include "PropertyDefinition.h"
 #include "PropertyDictionary.h"
-#include "PropertyIterators.h"
 #include "PropertyParser.h"
 #include "PropertySpecification.h"
 #include "RenderInterface.h"

+ 4 - 6
Include/Rocket/Core/Element.h

@@ -57,7 +57,7 @@ class ElementDefinition;
 class ElementDocument;
 class ElementScroll;
 class ElementStyle;
-class ElementStyleIterator;
+class PropertiesIteratorView;
 class FontFaceHandle;
 class PropertyDictionary;
 class RenderInterface;
@@ -260,12 +260,10 @@ public:
 	/// @return True if a new animation key was added.
 	bool AddAnimationKey(const String& property_name, const Property& target_value, float duration, Tween tween = Tween{});
 	
-	/// Iterators for the properties defined on this element.
-	/// @warning Modifying the element's properties or classes invalidates the iterators.
+	/// Iterator for the local (non-inherited) properties defined on this element.
+	/// @warning Modifying the element's properties or classes invalidates the iterator.
 	/// @return Iterator to the first property defined on this element.
-	ElementStyleIterator IteratePropertiesBegin() const;
-	/// @return Iterator to the one-past-the-last property defined on this element.
-	ElementStyleIterator IteratePropertiesEnd() const;
+	PropertiesIteratorView IterateLocalProperties() const;
 	///@}
 
 	/** @name Pseudo-classes

+ 78 - 0
Include/Rocket/Core/PropertiesIteratorView.h

@@ -0,0 +1,78 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#ifndef ROCKETCOREPROPERTIESITERATORVIEW_H
+#define ROCKETCOREPROPERTIESITERATORVIEW_H
+
+#include "Types.h"
+
+namespace Rocket {
+namespace Core {
+
+class PropertiesIterator;
+
+/**
+	Provides an iterator for properties defined in the element's style or definition.
+	Construct it through the desired Element.
+	Warning: Modifying the underlying style invalidates the iterator.
+
+	Usage:
+		for(auto it = element.IterateLocalProperties(); !it.AtEnd(); ++it) { ... }
+
+	Note: Not an std-style iterator. Implemented as a wrapper over the internal
+	iterator to avoid exposing internal headers to the user.
+
+	@author Michael R. P. Ragazzon
+ */
+
+class ROCKETCORE_API PropertiesIteratorView {
+public:
+	PropertiesIteratorView(std::unique_ptr<PropertiesIterator> ptr);
+	PropertiesIteratorView(PropertiesIteratorView&&) = default;
+	PropertiesIteratorView& operator=(PropertiesIteratorView&&) = default;
+	~PropertiesIteratorView();
+
+	PropertiesIteratorView& operator++();
+
+	// Returns true when all properties have been iterated over.
+	// @warning The getters and operator++ can only be called if the iterator is not at the end.
+	bool AtEnd() const;
+
+	PropertyId GetId() const;
+	const String& GetName() const;
+	const Property& GetProperty() const;
+
+	// Returns the list of pseudo classes which defines the current property, possibly empty.
+	const PseudoClassList& GetPseudoClassList() const;
+
+private:
+	std::unique_ptr<PropertiesIterator> ptr;
+};
+
+}
+}
+
+#endif

+ 0 - 124
Include/Rocket/Core/PropertyIterators.h

@@ -1,124 +0,0 @@
-/*
- * This source file is part of libRocket, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://www.librocket.com
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#ifndef ROCKETCOREPROPERTYITERATORS_H
-#define ROCKETCOREPROPERTYITERATORS_H
-
-#include "Types.h"
-
-namespace Rocket {
-namespace Core {
-
-/**
-	Provides iterators for properties defined in the element's style or definition.
-	@author Michael R. P. Ragazzon
- */
-
-
-// Iterates over the properties of an element definition matching the given pseudo classes.
-// Note: Modifying the underlying definition invalidates the iterator.
-// Note: 'pseudo_classes' must outlive the iterator.
-class ROCKETCORE_API ElementDefinitionIterator {
-public:
-	using difference_type = std::ptrdiff_t;
-	using value_type = std::pair<PropertyId, const Property&>;
-	using pointer = value_type*;
-	using reference = value_type&;
-	using iterator_category = std::input_iterator_tag;
-
-	using PropertyIt = PropertyMap::const_iterator;
-	using PseudoIt = PseudoClassPropertyDictionary::const_iterator;
-
-	ElementDefinitionIterator();
-	ElementDefinitionIterator(const PseudoClassList& pseudo_classes, PropertyIt it_properties, PseudoIt it_pseudo_class_properties, PropertyIt it_properties_end, PseudoIt it_pseudo_class_properties_end);
-	ElementDefinitionIterator& operator++();
-	bool operator==(const ElementDefinitionIterator& other) const { return pseudo_classes == other.pseudo_classes && it_properties == other.it_properties && it_pseudo_class_properties == other.it_pseudo_class_properties && i_pseudo_class == other.i_pseudo_class; }
-	bool operator!=(const ElementDefinitionIterator& other) const { return !(*this == other); }
-	
-	value_type operator*() const 
-	{
-		if (it_properties != it_properties_end)
-			return { it_properties->first, it_properties->second };
-		return { it_pseudo_class_properties->first,  it_pseudo_class_properties->second[i_pseudo_class].second };
-	}
-
-	// Return the list of pseudo classes which defines the current property, possibly null
-	const PseudoClassList* pseudo_class_list() const;
-
-private:
-	const PseudoClassList* pseudo_classes;
-	PropertyIt it_properties, it_properties_end;
-	PseudoIt it_pseudo_class_properties, it_pseudo_class_properties_end;
-	size_t i_pseudo_class = 0;
-
-	void proceed_to_next_valid();
-};
-
-
-
-// An iterator for local properties defined on an element.
-// Note: Modifying the underlying style invalidates the iterator.
-class ROCKETCORE_API ElementStyleIterator {
-public:
-	using difference_type = std::ptrdiff_t;
-	using value_type = std::pair<PropertyId, const Property&>;
-	using pointer = value_type *;
-	using reference = value_type &;
-	using iterator_category = std::input_iterator_tag;
-
-	using PropertyIt = PropertyMap::const_iterator;
-	using DefinitionIt = ElementDefinitionIterator;
-
-	ElementStyleIterator();
-	ElementStyleIterator(const PropertyMap* property_map, PropertyIt it_properties, DefinitionIt it_definition, PropertyIt it_properties_end, DefinitionIt it_definition_end);
-
-	ElementStyleIterator& operator++();
-	bool operator==(const ElementStyleIterator& other) const { return property_map == other.property_map && it_properties == other.it_properties && it_definition == other.it_definition; }
-	bool operator!=(const ElementStyleIterator& other) const { return !(*this == other); }
-
-	value_type operator*() const 
-	{
-		if (it_properties != it_properties_end)
-			return { it_properties->first, it_properties->second };
-		return *it_definition;
-	}
-
-	// Return the list of pseudo classes which defines the current property, possibly null
-	const PseudoClassList* pseudo_class_list() const;
-
-private:
-	const PropertyMap* property_map;
-	PropertyIt it_properties, it_properties_end;
-	DefinitionIt it_definition, it_definition_end;
-
-	void proceed_to_next_valid();
-};
-
-
-}
-}
-
-#endif

+ 113 - 0
Source/Core/DirtyPropertyList.h

@@ -0,0 +1,113 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#ifndef ROCKETCOREDIRTYPROPERTYLIST_H
+#define ROCKETCOREDIRTYPROPERTYLIST_H
+
+#include "../../Include/Rocket/Core/Types.h"
+#include "../../Include/Rocket/Core/ID.h"
+#include "../../Include/Rocket/Core/StyleSheetSpecification.h"
+#include <bitset>
+
+namespace Rocket {
+namespace Core {
+
+
+class DirtyPropertyList {
+private:
+	static constexpr size_t N = (size_t)PropertyId::NumDefinedIds;
+	std::bitset<N> dirty_set;
+	PropertyNameList dirty_custom_properties;
+
+public:
+	DirtyPropertyList(bool all_dirty = false)
+	{
+		static_assert((size_t)PropertyId::Invalid == 0, "DirtyPropertyList makes an assumption that PropertyId::Invalid is zero.");
+		if (all_dirty)
+			DirtyAll();
+	}
+
+	void Insert(PropertyId id) {
+		if ((size_t)id < N)
+			dirty_set.set((size_t)id);
+		else
+			dirty_custom_properties.insert(id);
+	}
+	void Insert(const PropertyNameList& properties) {
+		if (dirty_set.test(0)) return;
+		for (auto id : properties)
+			Insert(id);
+	}
+	void DirtyAll() {
+		// We are using PropertyId::Invalid (0) as a flag for all properties dirty.
+		// However, we set the whole set so that we don't have to do the extra check
+		// for the first bit in Contains().
+		dirty_set.set();
+	}
+	void Clear() {
+		dirty_set.reset();
+		dirty_custom_properties.clear();
+	}
+	void Remove(PropertyId id) {
+		if ((size_t)id < N)
+			dirty_set.reset((size_t)id);
+		else
+			dirty_custom_properties.erase(id);
+	}
+
+	bool Empty() const {
+		return dirty_set.none() && dirty_custom_properties.empty();
+	}
+	bool Contains(PropertyId id) const {
+		if ((size_t)id < N)
+			return dirty_set.test((size_t)id);
+		else if (dirty_set.test(0))
+			return true;
+		else
+			return dirty_custom_properties.count(id) == 1;
+	}
+	bool IsAllDirty() const {
+		return dirty_set.test(0);
+	}
+
+	PropertyNameList ToPropertyList() const {
+		if (IsAllDirty())
+			return StyleSheetSpecification::GetRegisteredProperties();
+
+		PropertyNameList property_list = dirty_custom_properties;
+		property_list.reserve(dirty_set.count());
+		for (size_t i = 1; i < N; i++)
+			if (dirty_set.test(i))
+				property_list.insert((PropertyId)i);
+		return property_list;
+	}
+};
+
+
+}
+}
+
+#endif

+ 6 - 8
Source/Core/Element.cpp

@@ -34,6 +34,7 @@
 #include <limits>
 #include "Clock.h"
 #include "ComputeProperty.h"
+#include "DirtyPropertyList.h"
 #include "ElementAnimation.h"
 #include "ElementBackground.h"
 #include "ElementBorder.h"
@@ -45,6 +46,7 @@
 #include "FontFaceHandle.h"
 #include "LayoutEngine.h"
 #include "PluginRegistry.h"
+#include "PropertiesIterator.h"
 #include "Pool.h"
 #include "StyleSheetParser.h"
 #include "XMLParseTools.h"
@@ -235,10 +237,10 @@ void Element::Update(float dp_ratio)
 		// Computed values are just calculated and can safely be used in OnPropertyChange.
 		// However, new properties set during this call will not be available until the next update loop.
 		// Enable ROCKET_DEBUG to get a warning when this happens.
-		if (dirty_properties.AllDirty())
+		if (dirty_properties.IsAllDirty())
 			OnPropertyChange(StyleSheetSpecification::GetRegisteredProperties());
 		else if(!dirty_properties.Empty())
-			OnPropertyChange(dirty_properties.GetList());
+			OnPropertyChange(dirty_properties.ToPropertyList());
 
 #ifdef ROCKET_DEBUG
 		if (style->AnyPropertiesDirty())
@@ -897,15 +899,11 @@ Vector2f Element::Project(const Vector2f& point) const noexcept
 	}
 }
 
-ElementStyleIterator Element::IteratePropertiesBegin() const
+PropertiesIteratorView Element::IterateLocalProperties() const
 {
-	return style->begin();
+	return PropertiesIteratorView(std::make_unique<PropertiesIterator>(style->Iterate()));
 }
 
-ElementStyleIterator Element::IteratePropertiesEnd() const
-{
-	return style->end();
-}
 
 // Sets or removes a pseudo-class on the element.
 void Element::SetPseudoClass(const String& pseudo_class, bool activate)

+ 0 - 9
Source/Core/ElementDefinition.cpp

@@ -29,7 +29,6 @@
 #include "ElementDefinition.h"
 #include "StyleSheetNode.h"
 #include "../../Include/Rocket/Core/Log.h"
-#include "../../Include/Rocket/Core/PropertyIterators.h"
 
 namespace Rocket {
 namespace Core {
@@ -222,14 +221,6 @@ bool ElementDefinition::IsStructurallyVolatile() const
 	return structurally_volatile;
 }
 
-ElementDefinitionIterator ElementDefinition::begin(const PseudoClassList& pseudo_classes) const {
-	return ElementDefinitionIterator(pseudo_classes, properties.GetProperties().begin(), pseudo_class_properties.begin(), properties.GetProperties().end(), pseudo_class_properties.end());
-}
-
-ElementDefinitionIterator ElementDefinition::end(const PseudoClassList& pseudo_classes) const {
-	return ElementDefinitionIterator(pseudo_classes, properties.GetProperties().end(), pseudo_class_properties.end(), properties.GetProperties().end(), pseudo_class_properties.end());
-}
-
 // Destroys the definition.
 void ElementDefinition::OnReferenceDeactivate()
 {

+ 2 - 4
Source/Core/ElementDefinition.h

@@ -85,10 +85,8 @@ public:
 	/// @return True if this definition is structurally volatile.
 	bool IsStructurallyVolatile() const;
 
-	/// Returns an iterator to the first property matching the active set of pseudo_classes.
-	ElementDefinitionIterator begin(const PseudoClassList& pseudo_classes) const;
-	/// Returns an iterator to the property following the last property matching the active set of pseudo_classes.
-	ElementDefinitionIterator end(const PseudoClassList& pseudo_classes) const;
+	const PropertyDictionary& GetProperties() const { return properties; }
+	const PseudoClassPropertyDictionary& GetPseudoClassProperties() const { return pseudo_class_properties; }
 
 	/// Returns true if the pseudo-class requirement of a rule is met by a list of an element's pseudo-classes.
 	static bool IsPseudoClassRuleApplicable(const PseudoClassList& rule_pseudo_classes, const PseudoClassList& element_pseudo_classes);

+ 2 - 2
Source/Core/ElementDocument.cpp

@@ -382,7 +382,7 @@ bool ElementDocument::IsLayoutDirty()
 
 void ElementDocument::DirtyDpProperties()
 {
-	GetStyle()->DirtyDpProperties();
+	GetStyle()->DirtyPropertiesWithUnitRecursive(Property::DP);
 }
 
 // Repositions the document if necessary.
@@ -392,7 +392,7 @@ void ElementDocument::OnPropertyChange(const PropertyNameList& changed_propertie
 
 	// If the document's font-size has been changed, we need to dirty all rem properties.
 	if (changed_properties.find(PropertyId::FontSize) != changed_properties.end())
-		GetStyle()->DirtyRemProperties();
+		GetStyle()->DirtyPropertiesWithUnitRecursive(Property::REM);
 
 	if (changed_properties.find(PropertyId::Top) != changed_properties.end() ||
 		changed_properties.find(PropertyId::Right) != changed_properties.end() ||

+ 41 - 79
Source/Core/ElementStyle.cpp

@@ -43,12 +43,13 @@
 #include "ElementDefinition.h"
 #include "FontFaceHandle.h"
 #include "ComputeProperty.h"
+#include "DirtyPropertyList.h"
+#include "PropertiesIterator.h"
 
 
 namespace Rocket {
 namespace Core {
 
-
 ElementStyle::ElementStyle(Element* _element) : dirty_properties(true)
 {
 	local_properties = NULL;
@@ -68,14 +69,11 @@ ElementStyle::~ElementStyle()
 }
 
 
-// Returns the element's definition, updating if necessary.
 const ElementDefinition* ElementStyle::GetDefinition()
 {
 	return definition;
 }
 
-
-
 // Returns one of this element's properties.
 const Property* ElementStyle::GetLocalProperty(PropertyId id, PropertyDictionary* local_properties, ElementDefinition* definition, const PseudoClassList& pseudo_classes)
 {
@@ -490,51 +488,22 @@ void ElementStyle::DirtyChildDefinitions()
 		element->GetChild(i)->GetStyle()->DirtyDefinition();
 }
 
-// Dirties rem properties.
-void ElementStyle::DirtyRemProperties()
-{
-	const PropertyNameList &properties = StyleSheetSpecification::GetRegisteredProperties();
-	PropertyNameList rem_properties;
-
-	// Dirty all the properties of this element that use the rem unit.
-	for (auto name_property_pair : *this)
-	{
-		PropertyId id = name_property_pair.first;
-		const Property& property = name_property_pair.second;
-		if (property.unit == Property::REM)
-			rem_properties.insert(id);
-	}
-
-	if (!rem_properties.empty())
-		DirtyProperties(rem_properties);
-
-	// Now dirty all of our descendant's properties that use the rem unit.
-	int num_children = element->GetNumChildren(true);
-	for (int i = 0; i < num_children; ++i)
-		element->GetChild(i)->GetStyle()->DirtyRemProperties();
-}
-
-void ElementStyle::DirtyDpProperties()
+void ElementStyle::DirtyPropertiesWithUnitRecursive(Property::Unit unit)
 {
-	const PropertyNameList &properties = StyleSheetSpecification::GetRegisteredProperties();
-	PropertyNameList dp_properties;
-
-	// Dirty all the properties of this element that use the dp unit.
-	for (auto name_property_pair : *this)
+	// Dirty all the properties of this element that use the unit.
+	for (auto it = Iterate(); !it.AtEnd(); ++it)
 	{
+		auto name_property_pair = *it;
 		PropertyId id = name_property_pair.first;
 		const Property& property = name_property_pair.second;
-		if (property.unit == Property::DP)
-			dp_properties.insert(id);
+		if (property.unit == unit)
+			DirtyProperty(id);
 	}
 
-	if (!dp_properties.empty())
-		DirtyProperties(dp_properties);
-
-	// Now dirty all of our descendant's properties that use the dp unit.
+	// Now dirty all of our descendant's properties that use the unit.
 	int num_children = element->GetNumChildren(true);
 	for (int i = 0; i < num_children; ++i)
-		element->GetChild(i)->GetStyle()->DirtyDpProperties();
+		element->GetChild(i)->GetStyle()->DirtyPropertiesWithUnitRecursive(unit);
 }
 
 bool ElementStyle::AnyPropertiesDirty() const 
@@ -542,38 +511,35 @@ bool ElementStyle::AnyPropertiesDirty() const
 	return !dirty_properties.Empty(); 
 }
 
-ElementStyleIterator ElementStyle::begin() const {
-	const PropertyMap* local = nullptr;
-	PropertyMap::const_iterator it_local_begin, it_local_end;
-	if (local_properties)
-	{
-		local = &local_properties->GetProperties();
-		it_local_begin = local->begin();
-		it_local_end = local->end();
-	}
-	ElementDefinitionIterator it_definition_begin, it_definition_end;
-	if (definition)
-	{
-		it_definition_begin = definition->begin(pseudo_classes);
-		it_definition_end = definition->end(pseudo_classes);
-	}
-	return ElementStyleIterator(local, it_local_begin, it_definition_begin, it_local_end, it_definition_end);
-}
+PropertiesIterator ElementStyle::Iterate() const {
+	// Note: Value initialized iterators are only guaranteed to compare equal in C++14, and only for iterators satisfying the ForwardIterator requirements.
+#ifdef _MSC_VER
+	// Null forward iterator supported since VS 2015
+	static_assert(_MSC_VER >= 1900, "Visual Studio 2015 or higher required, see comment.");
+#else
+	static_assert(__cplusplus >= 201402L, "C++14 or higher required, see comment.");
+#endif
 
-ElementStyleIterator ElementStyle::end() const {
-	const PropertyMap* local = nullptr;
-	PropertyMap::const_iterator it_local_end;
+	PropertyMap::const_iterator it_style_begin{}, it_style_end{};
 	if (local_properties)
 	{
-		local = &local_properties->GetProperties();
-		it_local_end = local->end();
+		const PropertyMap& property_map = local_properties->GetProperties();
+		it_style_begin = property_map.begin();
+		it_style_end = property_map.end();
 	}
-	ElementDefinitionIterator it_definition_end;
+	
+	PseudoClassPropertyDictionary::const_iterator it_pseudo{}, it_pseudo_end{};
+	PropertyMap::const_iterator it_base{}, it_base_end{};
 	if (definition)
 	{
-		it_definition_end = definition->end(pseudo_classes);
+		const PseudoClassPropertyDictionary& pseudo = definition->GetPseudoClassProperties();
+		const PropertyMap& base = definition->GetProperties().GetProperties();
+		it_pseudo = pseudo.begin();
+		it_pseudo_end = pseudo.end();
+		it_base = base.begin();
+		it_base_end = base.end();
 	}
-	return ElementStyleIterator(local, it_local_end, it_definition_end, it_local_end, it_definition_end);
+	return PropertiesIterator(pseudo_classes, it_style_begin, it_style_end, it_pseudo, it_pseudo_end, it_base, it_base_end);
 }
 
 // Sets a single property as dirty.
@@ -592,7 +558,6 @@ void ElementStyle::DirtyProperties(const PropertyNameList& properties)
 void ElementStyle::DirtyInheritedProperties(const PropertyNameList& properties)
 {
 	dirty_properties.Insert(properties);
-	return;
 }
 
 static void DirtyEmProperties(DirtyPropertyList& dirty_properties, Element* element)
@@ -704,10 +669,10 @@ DirtyPropertyList ElementStyle::ComputeValues(Style::ComputedValues& values, con
 		values.pointer_events = parent_values->pointer_events;
 	}
 
-
-	for(auto name_property_pair : *this)
+	for (auto it = Iterate(); !it.AtEnd(); ++it)
 	{
-		PropertyId id = name_property_pair.first;
+		auto name_property_pair = *it;
+		const PropertyId id = name_property_pair.first;
 		const Property* p = &name_property_pair.second;
 
 		using namespace Style;
@@ -931,14 +896,14 @@ DirtyPropertyList ElementStyle::ComputeValues(Style::ComputedValues& values, con
 
 		case PropertyId::Decorator:
 			values.decorator.clear();
-			// Usually the decorator is converted from string after the style sheet is set on the ElementDocument. However, if the
-			// user sets a decorator on the element's style, we may still get a string here which must be parsed and instanced.
 			if (p->unit == Property::DECORATOR)
 			{
 				values.decorator = p->Get<DecoratorList>();
 			}
 			else if (p->unit == Property::STRING)
 			{
+				// Usually the decorator is converted from string after the style sheet is set on the ElementDocument. However, if the
+				// user sets a decorator on the element's style, we may still get a string here which must be parsed and instanced.
 				if(const StyleSheet* style_sheet = GetStyleSheet())
 				{
 					String value = p->Get<String>();
@@ -961,7 +926,7 @@ DirtyPropertyList ElementStyle::ComputeValues(Style::ComputedValues& values, con
 
 	bool all_inherited_dirty = false;
 
-	if (dirty_properties.AllDirty())
+	if (dirty_properties.IsAllDirty())
 	{
 		all_inherited_dirty = true;
 	}
@@ -969,11 +934,8 @@ DirtyPropertyList ElementStyle::ComputeValues(Style::ComputedValues& values, con
 	{
 		// Find all dirtied properties which are also inherited
 		const auto& inherited_properties = StyleSheetSpecification::GetRegisteredInheritedProperties();
-		std::set_intersection(
-			inherited_properties.begin(), inherited_properties.end(), 
-			dirty_properties.GetList().begin(), dirty_properties.GetList().end(), 
-			std::back_inserter(dirty_inherited.modify_container())
-		);
+		for (PropertyId id : inherited_properties)
+			dirty_properties.Insert(id);
 	}
 
 	if (all_inherited_dirty || dirty_inherited.size() > 0)
@@ -986,7 +948,7 @@ DirtyPropertyList ElementStyle::ComputeValues(Style::ComputedValues& values, con
 			child->GetStyle()->dirty_properties.Insert(dirty_inherited_ref);
 		}
 	}
-
+	
 	DirtyPropertyList result(std::move(dirty_properties));
 	dirty_properties.Clear();
 	return result;

+ 9 - 57
Source/Core/ElementStyle.h

@@ -28,58 +28,14 @@
 #ifndef ROCKETCOREELEMENTSTYLE_H
 #define ROCKETCOREELEMENTSTYLE_H
 
-#include "ElementDefinition.h"
 #include "../../Include/Rocket/Core/Types.h"
+#include "DirtyPropertyList.h"
 
 namespace Rocket {
 namespace Core {
 
-
-class DirtyPropertyList {
-private:
-	bool all_dirty = false;
-	PropertyNameList dirty_list;
-
-public:
-	DirtyPropertyList(bool all_dirty = false) : all_dirty(all_dirty) {}
-
-	void Insert(PropertyId id) {
-		if (all_dirty) return;
-		dirty_list.insert(id);
-	}
-	void Insert(const PropertyNameList& properties) {
-		if (all_dirty) return;
-		// @performance: Can be made O(N+M)
-		dirty_list.insert(properties.begin(), properties.end());
-	}
-	void DirtyAll() {
-		all_dirty = true;
-		dirty_list.clear();
-	}
-	void Clear() {
-		all_dirty = false;
-		dirty_list.clear();
-	}
-
-	bool Empty() const {
-		return !all_dirty && dirty_list.empty();
-	}
-	bool Contains(PropertyId id) const {
-		if (all_dirty)
-			return true;
-		auto it = dirty_list.find(id);
-		return (it != dirty_list.end());
-	}
-	bool AllDirty() const {
-		return all_dirty;
-	}
-	const PropertyNameList& GetList() const {
-		return dirty_list;
-	}
-};
-
-
-
+class ElementDefinition;
+class PropertiesIterator;
 
 /**
 	Manages an element's style and property information.
@@ -94,7 +50,7 @@ public:
 	ElementStyle(Element* element);
 	~ElementStyle();
 
-	/// Returns the element's definition, updating if necessary.
+	/// Returns the element's definition.
 	const ElementDefinition* GetDefinition();
 	
 	/// Update this definition if required
@@ -165,10 +121,8 @@ public:
 	/// Dirty all child definitions
 	void DirtyChildDefinitions();
 
-	/// Dirties rem properties.
-	void DirtyRemProperties();
-	/// Dirties dp properties.
-	void DirtyDpProperties();
+	/// Dirties all properties with a given unit on the current element and recursively on all children.
+	void DirtyPropertiesWithUnitRecursive(Property::Unit unit);
 
 	/// Returns true if any properties are dirty such that computed values need to be recomputed
 	bool AnyPropertiesDirty() const;
@@ -177,11 +131,9 @@ public:
 	/// Must be called in correct order, always parent before its children.
 	DirtyPropertyList ComputeValues(Style::ComputedValues& values, const Style::ComputedValues* parent_values, const Style::ComputedValues* document_values, bool values_are_default_initialized, float dp_ratio);
 
-	/// Returns an iterator to the first property defined on this element.
-	/// Note: Modifying the element's style invalidates its iterators.
-	ElementStyleIterator begin() const;
-	/// Returns an iterator to the property following the last property defined on this element.
-	ElementStyleIterator end() const;
+	/// Returns an iterator for iterating the local properties of this element.
+	/// Note: Modifying the element's style invalidates its iterator.
+	PropertiesIterator Iterate() const;
 
 private:
 	// Sets a single property as dirty.

+ 147 - 0
Source/Core/PropertiesIterator.h

@@ -0,0 +1,147 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#ifndef ROCKETCOREPROPERTIESITERATOR_H
+#define ROCKETCOREPROPERTIESITERATOR_H
+
+#include "../../Include/Rocket/Core/Types.h"
+#include "DirtyPropertyList.h"
+#include "ElementDefinition.h"
+
+namespace Rocket {
+namespace Core {
+
+
+
+// An iterator for local properties defined on an element.
+// Note: Modifying the underlying style invalidates the iterator.
+class PropertiesIterator {
+public:
+	using ValueType = std::pair<PropertyId, const Property&>;
+	using PropertyIt = PropertyMap::const_iterator;
+	using PseudoIt = PseudoClassPropertyDictionary::const_iterator;
+
+	PropertiesIterator(const PseudoClassList& element_pseudo_classes, PropertyIt it_style, PropertyIt it_style_end, PseudoIt it_pseudo, PseudoIt it_pseudo_end, PropertyIt it_base, PropertyIt it_base_end)
+		: element_pseudo_classes(&element_pseudo_classes), it_style(it_style), it_style_end(it_style_end), it_pseudo(it_pseudo), it_pseudo_end(it_pseudo_end), it_base(it_base), it_base_end(it_base_end)
+	{
+		if (this->element_pseudo_classes->empty())
+			this->it_pseudo = this->it_pseudo_end;
+		ProceedToNextValid();
+	}
+
+	PropertiesIterator& operator++() {
+		if (it_style != it_style_end)
+			// First, we iterate over the local properties
+			++it_style;
+		else if (it_pseudo != it_pseudo_end)
+			// Then, we iterate over the properties given by the pseudo classes in the element's definition
+			++i_pseudo_class;
+		else
+			// Finally, we iterate over the base properties given by the element's definition
+			++it_base;
+		// If we reached the end of one of the iterator pairs, we need to continue iteration on the next pair.
+		ProceedToNextValid();
+		return *this;
+	}
+
+	ValueType operator*() const
+	{
+		if (it_style != it_style_end)
+			return { it_style->first, it_style->second };
+		if (it_pseudo != it_pseudo_end)
+			return { it_pseudo->first, it_pseudo->second[i_pseudo_class].second };
+		return { it_base->first, it_base->second };
+	}
+
+	bool AtEnd() const {
+		return at_end;
+	}
+
+	// Return the list of pseudo classes which defines the current property, possibly null.
+	const PseudoClassList* GetPseudoClassList() const
+	{
+		if (it_style == it_style_end && it_pseudo != it_pseudo_end)
+			return &it_pseudo->second[i_pseudo_class].first;
+		return nullptr;
+	}
+
+private:
+	const PseudoClassList* element_pseudo_classes;
+	DirtyPropertyList iterated_properties;
+	PropertyIt it_style, it_style_end;
+	PseudoIt it_pseudo, it_pseudo_end;
+	PropertyIt it_base, it_base_end;
+	size_t i_pseudo_class = 0;
+	bool at_end = false;
+
+	inline bool IsDirtyRemove(PropertyId id)
+	{
+		if (!iterated_properties.Contains(id))
+		{
+			iterated_properties.Insert(id);
+			return true;
+		}
+		return false;
+	}
+
+	inline void ProceedToNextValid() {
+		for (; it_style != it_style_end; ++it_style)
+		{
+			if (IsDirtyRemove(it_style->first))
+				return;
+		}
+
+		// Iterate over all the pseudo classes and match the applicable rules
+		for (; it_pseudo != it_pseudo_end; ++it_pseudo)
+		{
+			const PseudoClassPropertyList& pseudo_list = it_pseudo->second;
+			for (; i_pseudo_class < pseudo_list.size(); ++i_pseudo_class)
+			{
+				if (ElementDefinition::IsPseudoClassRuleApplicable(pseudo_list[i_pseudo_class].first, *element_pseudo_classes))
+				{
+					if (IsDirtyRemove(it_pseudo->first))
+						return;
+				}
+			}
+			i_pseudo_class = 0;
+		}
+
+		for (; it_base != it_base_end; ++it_base)
+		{
+			if (IsDirtyRemove(it_base->first))
+				return;
+		}
+
+		// All iterators are now at the end
+		at_end = true;
+	}
+};
+
+
+}
+}
+
+#endif

+ 78 - 0
Source/Core/PropertiesIteratorView.cpp

@@ -0,0 +1,78 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include "../../Include/Rocket/Core/PropertiesIteratorView.h"
+#include "PropertiesIterator.h"
+
+namespace Rocket {
+namespace Core {
+
+
+
+PropertiesIteratorView::PropertiesIteratorView(std::unique_ptr<PropertiesIterator> ptr) : ptr(std::move(ptr)) {}
+
+PropertiesIteratorView::~PropertiesIteratorView()
+{}
+
+PropertiesIteratorView& PropertiesIteratorView::operator++()
+{
+	++(*ptr);
+	return *this;
+}
+
+PropertyId PropertiesIteratorView::GetId() const
+{
+	return (*(*ptr)).first;
+}
+
+const String& PropertiesIteratorView::GetName() const
+{
+	return Core::StyleSheetSpecification::GetPropertyName(GetId());
+}
+
+const Property& PropertiesIteratorView::GetProperty() const
+{
+	return (*(*ptr)).second;
+}
+
+bool PropertiesIteratorView::AtEnd() const {
+	return ptr->AtEnd();
+}
+
+const PseudoClassList& PropertiesIteratorView::GetPseudoClassList() const
+{
+	static const PseudoClassList empty_pseudo_class_list;
+	const PseudoClassList* pseudo_list_ptr = ptr->GetPseudoClassList();
+	if (!pseudo_list_ptr)
+		return empty_pseudo_class_list;
+
+	return *pseudo_list_ptr;
+}
+
+}
+}

+ 0 - 139
Source/Core/PropertyIterators.cpp

@@ -1,139 +0,0 @@
-/*
- * This source file is part of libRocket, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://www.librocket.com
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include "precompiled.h"
-#include "../../Include/Rocket/Core/PropertyIterators.h"
-#include "ElementDefinition.h"
-
-namespace Rocket {
-namespace Core {
-
-
-// Return the list of pseudo classes which defines the current property, possibly null
-ElementDefinitionIterator::ElementDefinitionIterator() : pseudo_classes(nullptr) {}
-
-ElementDefinitionIterator::ElementDefinitionIterator(const PseudoClassList& pseudo_classes, PropertyIt it_properties, PseudoIt it_pseudo_class_properties, PropertyIt it_properties_end, PseudoIt it_pseudo_class_properties_end)
-	: pseudo_classes(&pseudo_classes), it_properties(it_properties), it_pseudo_class_properties(it_pseudo_class_properties), it_properties_end(it_properties_end), it_pseudo_class_properties_end(it_pseudo_class_properties_end)
-{
-	proceed_to_next_valid();
-}
-
-const PseudoClassList* ElementDefinitionIterator::pseudo_class_list() const
-{
-	if (it_properties != it_properties_end)
-		return nullptr;
-	return &it_pseudo_class_properties->second[i_pseudo_class].first;
-}
-
-ElementDefinitionIterator& ElementDefinitionIterator::operator++()
-{
-	// The iteration proceeds as follows:
-	//  1. Iterate over all the default properties of the element (with no pseudo classes)
-	//  2. Iterate over each pseudo class that has a definition for this property,
-	//      testing each one to see if it matches the currently set pseudo classes.
-	if (it_properties != it_properties_end)
-	{
-		++it_properties;
-		proceed_to_next_valid();
-		return *this;
-	}
-	++i_pseudo_class;
-	proceed_to_next_valid();
-	return *this;
-}
-
-void ElementDefinitionIterator::proceed_to_next_valid()
-{
-	if (it_properties == it_properties_end)
-	{
-		// Iterate over all the pseudo classes and match the applicable rules
-		for (; it_pseudo_class_properties != it_pseudo_class_properties_end; ++it_pseudo_class_properties)
-		{
-			const PseudoClassPropertyList& pseudo_list = it_pseudo_class_properties->second;
-			for (; i_pseudo_class < pseudo_list.size(); ++i_pseudo_class)
-			{
-				if (ElementDefinition::IsPseudoClassRuleApplicable(pseudo_list[i_pseudo_class].first, *pseudo_classes))
-				{
-					return;
-				}
-			}
-			i_pseudo_class = 0;
-		}
-	}
-}
-
-ElementStyleIterator& ElementStyleIterator::operator++()
-{
-	// First, we iterate over the local properties
-	if (it_properties != it_properties_end)
-	{
-		++it_properties;
-		proceed_to_next_valid();
-		return *this;
-	}
-	// Then, we iterate over the properties given by the element's definition
-	++it_definition;
-	proceed_to_next_valid();
-	return *this;
-}
-
-
-void ElementStyleIterator::proceed_to_next_valid()
-{
-	// If we've reached the end of the local properties, continue iteration on the definition
-	if (it_properties == it_properties_end)
-	{
-		for (; it_definition != it_definition_end; ++it_definition)
-		{
-			// Skip this property if it has been overridden by the element's local properties
-			if (property_map && property_map->count((*it_definition).first))
-				continue;
-			return;
-		}
-	}
-}
-
-
-// Return the list of pseudo classes which defines the current property, possibly null
-
-const PseudoClassList* ElementStyleIterator::pseudo_class_list() const
-{
-	if (it_properties != it_properties_end)
-		return nullptr;
-	return it_definition.pseudo_class_list();
-}
-
-ElementStyleIterator::ElementStyleIterator() : property_map(nullptr) {}
-
-ElementStyleIterator::ElementStyleIterator(const PropertyMap* property_map, PropertyIt it_properties, DefinitionIt it_definition, PropertyIt it_properties_end, DefinitionIt it_definition_end)
-	: property_map(property_map), it_properties(it_properties), it_definition(it_definition), it_properties_end(it_properties_end), it_definition_end(it_definition_end)
-{
-	proceed_to_next_valid();
-}
-
-}
-}

+ 6 - 11
Source/Debugger/ElementInfo.cpp

@@ -27,7 +27,7 @@
 
 #include "ElementInfo.h"
 #include "../../Include/Rocket/Core/Property.h"
-#include "../../Include/Rocket/Core/PropertyIterators.h"
+#include "../../Include/Rocket/Core/PropertiesIteratorView.h"
 #include "../../Include/Rocket/Core/Factory.h"
 #include "../../Include/Rocket/Core/StyleSheet.h"
 #include "../../Include/Rocket/Core/StyleSheetSpecification.h"
@@ -440,22 +440,17 @@ void ElementInfo::BuildElementPropertiesRML(Core::String& property_rml, Core::El
 {
 	NamedPropertyMap property_map;
 
-	const Core::PseudoClassList empty_property_pseudo_classes;
-
-	auto it_end = element->IteratePropertiesEnd();
-	for(auto it = element->IteratePropertiesBegin(); it != it_end; ++it)
+	for(auto it = element->IterateLocalProperties(); !it.AtEnd(); ++it)
 	{
-		const Core::PropertyId property_id = (*it).first;
-		const Core::String& property_name = Core::StyleSheetSpecification::GetPropertyName((*it).first);
-		const Core::Property* property = &(*it).second;
-		const Core::PseudoClassList* property_pseudo_classes_ptr = it.pseudo_class_list();
+		const Core::PropertyId property_id = it.GetId();
+		const Core::String& property_name = it.GetName();
+		const Core::Property* property = &it.GetProperty();
+		const Core::PseudoClassList& property_pseudo_classes = it.GetPseudoClassList();
 
 		// Check that this property isn't overridden or just not inherited.
 		if (primary_element->GetProperty(property_id) != property)
 			continue;
 
-		const Core::PseudoClassList& property_pseudo_classes = (property_pseudo_classes_ptr ? *property_pseudo_classes_ptr : empty_property_pseudo_classes);
-
 		NamedPropertyMap::iterator i = property_map.find(property_pseudo_classes);
 		if (i == property_map.end())
 			property_map[property_pseudo_classes] = NamedPropertyList(1, NamedProperty(property_name, property));