Ver código fonte

Merge branch 'property_id' into performance

# Conflicts:
#	Build/cmake/FileList.cmake
#	Include/Rocket/Core/Element.h
#	Source/Core/Element.cpp
#	Source/Core/ElementAnimation.cpp
#	Source/Core/ElementAnimation.h
#	Source/Core/ElementStyle.cpp
#	Source/Core/ElementStyle.h
Michael Ragazzon 6 anos atrás
pai
commit
93dd452fbd
100 arquivos alterados com 1430 adições e 1200 exclusões
  1. 7 6
      Build/cmake/FileList.cmake
  2. 2 4
      Include/Rocket/Core/Animation.h
  3. 2 0
      Include/Rocket/Core/ComputedValues.h
  4. 6 0
      Include/Rocket/Core/Containers/chobo/flat_map.hpp
  5. 6 0
      Include/Rocket/Core/Containers/chobo/flat_set.hpp
  6. 1 1
      Include/Rocket/Core/Containers/robin_hood.h
  7. 2 1
      Include/Rocket/Core/Core.h
  8. 8 32
      Include/Rocket/Core/Decorator.h
  9. 23 16
      Include/Rocket/Core/DecoratorInstancer.h
  10. 12 27
      Include/Rocket/Core/Element.h
  11. 6 5
      Include/Rocket/Core/Factory.h
  12. 2 2
      Include/Rocket/Core/FontEffectInstancer.h
  13. 117 0
      Include/Rocket/Core/ID.h
  14. 78 0
      Include/Rocket/Core/PropertiesIteratorView.h
  15. 1 0
      Include/Rocket/Core/Property.h
  16. 8 3
      Include/Rocket/Core/PropertyDefinition.h
  17. 4 4
      Include/Rocket/Core/PropertyDictionary.h
  18. 0 124
      Include/Rocket/Core/PropertyIterators.h
  19. 136 26
      Include/Rocket/Core/PropertySpecification.h
  20. 95 0
      Include/Rocket/Core/Spritesheet.h
  21. 1 0
      Include/Rocket/Core/String.h
  22. 7 0
      Include/Rocket/Core/StringUtilities.h
  23. 34 8
      Include/Rocket/Core/StyleSheet.h
  24. 20 4
      Include/Rocket/Core/StyleSheetSpecification.h
  25. 6 0
      Include/Rocket/Core/Texture.h
  26. 0 1
      Include/Rocket/Core/Transform.h
  27. 41 1
      Include/Rocket/Core/TypeConverter.h
  28. 0 67
      Include/Rocket/Core/TypeConverter.inl
  29. 19 12
      Include/Rocket/Core/Types.h
  30. 2 0
      Include/Rocket/Core/Variant.h
  31. 4 0
      Include/Rocket/Core/Variant.inl
  32. 16 0
      Include/Rocket/Core/Vector2.h
  33. 29 0
      Include/Rocket/Core/Vector2.inl
  34. 1 2
      Samples/assets/cursor.rml
  35. 185 108
      Samples/assets/invader.rcss
  36. 4 4
      Samples/basic/animation/src/main.cpp
  37. 3 2
      Samples/basic/benchmark/src/main.cpp
  38. 1 2
      Samples/basic/drag/data/icon.rcss
  39. 3 2
      Samples/basic/drag/src/Inventory.cpp
  40. 2 2
      Samples/basic/transform/src/main.cpp
  41. 23 24
      Samples/basic/treeview/data/treeview.rml
  42. 11 8
      Samples/invaders/data/background.rml
  43. 7 14
      Samples/invaders/data/game.rml
  44. 1 2
      Samples/invaders/data/help.rml
  45. 2 4
      Samples/invaders/data/high_score.rml
  46. 1 2
      Samples/invaders/data/main_menu.rml
  47. 1 3
      Samples/invaders/data/options.rml
  48. 1 2
      Samples/invaders/data/pause.rml
  49. 1 2
      Samples/invaders/data/start_game.rml
  50. 7 20
      Samples/invaders/src/DecoratorInstancerDefender.cpp
  51. 4 7
      Samples/invaders/src/DecoratorInstancerDefender.h
  52. 17 31
      Samples/invaders/src/DecoratorInstancerStarfield.cpp
  53. 4 7
      Samples/invaders/src/DecoratorInstancerStarfield.h
  54. 2 2
      Samples/invaders/src/EventHandlerOptions.cpp
  55. 2 7
      Samples/invaders/src/main.cpp
  56. 11 10
      Samples/luainvaders/data/background.rml
  57. 5 12
      Samples/luainvaders/data/game.rml
  58. 1 2
      Samples/luainvaders/data/help.rml
  59. 3 6
      Samples/luainvaders/data/high_score.rml
  60. 1 2
      Samples/luainvaders/data/main_menu.rml
  61. 1 3
      Samples/luainvaders/data/options.rml
  62. 1 2
      Samples/luainvaders/data/pause.rml
  63. 1 2
      Samples/luainvaders/data/start_game.rml
  64. 6 19
      Samples/luainvaders/src/DecoratorInstancerDefender.cpp
  65. 4 7
      Samples/luainvaders/src/DecoratorInstancerDefender.h
  66. 17 32
      Samples/luainvaders/src/DecoratorInstancerStarfield.cpp
  67. 4 7
      Samples/luainvaders/src/DecoratorInstancerStarfield.h
  68. 2 7
      Samples/luainvaders/src/main.cpp
  69. 70 41
      Samples/tutorial/datagrid/data/tutorial.rcss
  70. 8 9
      Samples/tutorial/datagrid/data/tutorial.rml
  71. 6 7
      Samples/tutorial/datagrid/src/DecoratorInstancerDefender.cpp
  72. 9 4
      Samples/tutorial/datagrid/src/DecoratorInstancerDefender.h
  73. 1 3
      Samples/tutorial/datagrid/src/main.cpp
  74. 70 41
      Samples/tutorial/datagrid_tree/data/tutorial.rcss
  75. 52 26
      Samples/tutorial/datagrid_tree/data/tutorial.rml
  76. 6 7
      Samples/tutorial/datagrid_tree/src/DecoratorInstancerDefender.cpp
  77. 9 4
      Samples/tutorial/datagrid_tree/src/DecoratorInstancerDefender.h
  78. 1 3
      Samples/tutorial/datagrid_tree/src/main.cpp
  79. 20 9
      Samples/tutorial/template/data/tutorial.rcss
  80. 1 2
      Samples/tutorial/tutorial_drag/data/tutorial.rcss
  81. 2 2
      Samples/tutorial/tutorial_drag/src/Inventory.cpp
  82. 8 7
      Source/Controls/ElementDataGrid.cpp
  83. 1 1
      Source/Controls/ElementDataGridCell.cpp
  84. 6 6
      Source/Controls/ElementDataGridRow.cpp
  85. 2 2
      Source/Controls/ElementFormControl.cpp
  86. 7 6
      Source/Controls/ElementFormControlTextArea.cpp
  87. 5 5
      Source/Controls/ElementTabSet.cpp
  88. 2 2
      Source/Controls/ElementTextSelection.cpp
  89. 2 2
      Source/Controls/InputTypeText.cpp
  90. 9 8
      Source/Controls/WidgetDropDown.cpp
  91. 3 3
      Source/Controls/WidgetSlider.cpp
  92. 5 4
      Source/Controls/WidgetTextInput.cpp
  93. 4 4
      Source/Core/Context.cpp
  94. 35 44
      Source/Core/Decorator.cpp
  95. 5 6
      Source/Core/DecoratorInstancer.cpp
  96. 0 64
      Source/Core/DecoratorNone.h
  97. 0 61
      Source/Core/DecoratorNoneInstancer.cpp
  98. 0 63
      Source/Core/DecoratorNoneInstancer.h
  99. 37 37
      Source/Core/DecoratorTiled.cpp
  100. 9 5
      Source/Core/DecoratorTiled.h

+ 7 - 6
Build/cmake/FileList.cmake

@@ -12,8 +12,6 @@ set(Core_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/ComputeProperty.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancerDefault.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DebugFont.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNone.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNoneInstancer.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiled.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBox.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBoxInstancer.h
@@ -24,6 +22,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
@@ -61,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
@@ -163,15 +163,16 @@ set(Core_PUB_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Matrix4.inl
     ${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
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/RenderInterface.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ScriptInterface.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Spritesheet.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Stream.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StreamMemory.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/String.h
@@ -221,8 +222,6 @@ set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/Core.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Decorator.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNone.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNoneInstancer.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiled.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBox.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBoxInstancer.cpp
@@ -291,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
@@ -304,6 +303,7 @@ set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertySpecification.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/ReferenceCountable.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/RenderInterface.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Spritesheet.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Stream.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/StreamFile.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/StreamMemory.cpp
@@ -340,6 +340,7 @@ set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/Transform.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/TransformPrimitive.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/TransformState.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/TypeConverter.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/UnicodeRange.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/URL.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Variant.cpp

+ 2 - 4
Include/Rocket/Core/Animation.h

@@ -48,11 +48,9 @@ struct Animation {
 	String name;
 };
 
-typedef std::vector<Animation> AnimationList;
-
 /* Data parsed from the 'transition' property. */
 struct Transition {
-	String name;
+	PropertyId id;
 	Tween tween;
 	float duration = 0.0f;
 	float delay = 0.0f;
@@ -71,7 +69,7 @@ struct TransitionList {
 
 inline bool operator==(const Animation& a, const Animation& b) { return a.duration == b.duration && a.tween == b.tween && a.delay == b.delay && a.alternate == b.alternate && a.paused == b.paused && a.num_iterations == b.num_iterations && a.name == b.name; }
 inline bool operator!=(const Animation& a, const Animation& b) { return !(a == b); }
-inline bool operator==(const Transition& a, const Transition& b) { return a.name == b.name && a.tween == b.tween && a.duration == b.duration && a.delay == b.delay && a.reverse_adjustment_factor == b.reverse_adjustment_factor; }
+inline bool operator==(const Transition& a, const Transition& b) { return a.id == b.id && a.tween == b.tween && a.duration == b.duration && a.delay == b.delay && a.reverse_adjustment_factor == b.reverse_adjustment_factor; }
 inline bool operator!=(const Transition& a, const Transition& b) { return !(a == b); }
 inline bool operator==(const TransitionList& a, const TransitionList& b) { return a.none == b.none && a.all == b.all && a.transitions == b.transitions; }
 inline bool operator!=(const TransitionList& a, const TransitionList& b) { return !(a == b); }

+ 2 - 0
Include/Rocket/Core/ComputedValues.h

@@ -198,6 +198,8 @@ struct ComputedValues
 
 	TransitionList transition;
 	AnimationList animation;
+
+	DecoratorList decorator;
 };
 }
 

+ 6 - 0
Include/Rocket/Core/Containers/chobo/flat_map.hpp

@@ -456,6 +456,12 @@ bool operator!=(const flat_map<Key, T, Compare, Container>& a, const flat_map<Ke
     return a.container() != b.container();
 }
 
+template <typename Key, typename T, typename Compare, typename Container>
+bool operator<(const flat_map<Key, T, Compare, Container>& a, const flat_map<Key, T, Compare, Container>& b)
+{
+	return a.container() < b.container();
+}
+
 }
 }
 }

+ 6 - 0
Include/Rocket/Core/Containers/chobo/flat_set.hpp

@@ -342,6 +342,12 @@ bool operator!=(const flat_set<T, Compare, Container>& a, const flat_set<T, Comp
     return a.container() != b.container();
 }
 
+template <typename T, typename Compare, typename Container>
+bool operator<(const flat_set<T, Compare, Container>& a, const flat_set<T, Compare, Container>& b)
+{
+	return a.container() < b.container();
+}
+
 }
 }
 }

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

@@ -1250,7 +1250,7 @@ public:
             // it will be the end() iterator.
             mKeyVals = reinterpret_cast<Node*>(&mMask);
             // we need to point somewhere thats 0 as long as we're empty
-            mInfo = reinterpret_cast<uint8_t*>(mMask);
+            mInfo = reinterpret_cast<uint8_t*>(&mMask);
             Hash::operator=(static_cast<const Hash&>(o));
             KeyEqual::operator=(static_cast<const KeyEqual&>(o));
             DataPool::operator=(static_cast<DataPool const&>(o));

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

@@ -62,13 +62,14 @@
 #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"
+#include "Spritesheet.h"
 #include "String.h"
 #include "StyleSheet.h"
 #include "StyleSheetKeywords.h"

+ 8 - 32
Include/Rocket/Core/Decorator.h

@@ -28,7 +28,6 @@
 #ifndef ROCKETCOREDECORATOR_H
 #define ROCKETCOREDECORATOR_H
 
-#include "ReferenceCountable.h"
 #include <vector>
 #include "Header.h"
 #include "Texture.h"
@@ -50,7 +49,7 @@ class TextureResource;
 	@author Peter Curry
  */
 
-class ROCKETCORE_API Decorator : public ReferenceCountable
+class ROCKETCORE_API Decorator
 {
 public:
 	Decorator();
@@ -64,22 +63,6 @@ public:
 	/// @param[in] element_data The element data handle to release.
 	virtual void ReleaseElementData(DecoratorDataHandle element_data) = 0;
 
-	/// Sets the z-index of the decorator. A decorator with a higher z-index will be rendered after a decorator
-	/// with a lower z-index. By default, all decorators have a z-index of 0.
-	/// @param[in] z-index The new z-index of the decorator.
-	void SetZIndex(float z_index);
-	/// Returns the decorator's z-index.
-	/// @return The z-index of the decorator.
-	float GetZIndex() const;
-
-	/// Sets the specificity of the decorator.
-	/// @param[in] specificity The specificity of the decorator.
-	void SetSpecificity(int specificity);
-	/// Returns the specificity of the decorator. This is used when multiple pseudo-classes are active on an
-	/// element, each with similarly-named decorators.
-	/// @return The specificity of the decorator.
-	int GetSpecificity() const;
-
 	/// Called to render the decorator on an element.
 	/// @param[in] element The element to render the decorator on.
 	/// @param[in] element_data The handle to the data generated by the decorator for the element.
@@ -89,32 +72,25 @@ public:
 	static const DecoratorDataHandle INVALID_DECORATORDATAHANDLE = 0;
 
 protected:
-	/// Releases the decorator through its instancer.
-	virtual void OnReferenceDeactivate();
-
 	/// Attempts to load a texture into the list of textures in use by the decorator.
 	/// @param[in] texture_name The name of the texture to load.
 	/// @param[in] rcss_path The RCSS file the decorator definition was loaded from; this is used to resolve relative paths.
 	/// @return The index of the texture if the load was successful, or -1 if the load failed.
 	int LoadTexture(const String& texture_name, const String& rcss_path);
+	/// Adds a texture if it is valid into the list of textures in use by the decorator.
+	/// @param[in] texture The texture to add.
+	/// @return The index of the texture if it is successful, or -1 if it is invalid.
+	int AddTexture(const Texture& texture);
 	/// Returns one of the decorator's previously loaded textures.
 	/// @param[in] index The index of the desired texture.
 	/// @return The texture at the appropriate index, or NULL if the index was invalid.
 	const Texture* GetTexture(int index = 0) const;
 
 private:
-	DecoratorInstancer* instancer;
-
-	// The z-index of this decorator, used to resolve render order when multiple decorators are rendered
-	// simultaneously on the same element.
-	float z_index;
-	// The maximum specificity of the properties used to define the decorator.
-	int specificity;
-
 	// Stores a list of textures in use by this decorator.
-	std::vector< Texture > textures;
-
-	friend class Factory;
+	// Optimized for the common case of a single texture.
+	Texture first_texture;
+	std::vector< Texture > additional_textures;
 };
 
 }

+ 23 - 16
Include/Rocket/Core/DecoratorInstancer.h

@@ -28,7 +28,6 @@
 #ifndef ROCKETCOREDECORATORINSTANCER_H
 #define ROCKETCOREDECORATORINSTANCER_H
 
-#include "ReferenceCountable.h"
 #include "Header.h"
 #include "PropertyDictionary.h"
 #include "PropertySpecification.h"
@@ -36,7 +35,11 @@
 namespace Rocket {
 namespace Core {
 
+struct Sprite;
+class StyleSheet;
 class Decorator;
+class DecoratorInstancerInterface;
+
 
 /**
 	An element instancer provides a method for allocating and deallocating decorators.
@@ -47,23 +50,18 @@ class Decorator;
 	@author Peter Curry
  */
 
-class ROCKETCORE_API DecoratorInstancer : public ReferenceCountable
+class ROCKETCORE_API DecoratorInstancer
 {
 public:
 	DecoratorInstancer();
 	virtual ~DecoratorInstancer();
 
 	/// Instances a decorator given the property tag and attributes from the RCSS file.
-	/// @param[in] name The type of decorator desired. For example, "background-decorator: simple;" is declared as type "simple".
+	/// @param[in] name The type of decorator desired. For example, "decorator: simple(...);" is declared as type "simple".
 	/// @param[in] properties All RCSS properties associated with the decorator.
-	/// @return The decorator if it was instanced successfully, NULL if an error occured.
-	virtual Decorator* InstanceDecorator(const String& name, const PropertyDictionary& properties) = 0;
-	/// Releases the given decorator.
-	/// @param[in] decorator Decorator to release. This is guaranteed to have been constructed by this instancer.
-	virtual void ReleaseDecorator(Decorator* decorator) = 0;
-
-	/// Releases the instancer.
-	virtual void Release() = 0;
+	/// @param[in] interface An interface for querying the active style sheet.
+	/// @return A shared_ptr to the decorator if it was instanced successfully.
+	virtual std::shared_ptr<Decorator> InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) = 0;
 
 	/// Returns the property specification associated with the instancer.
 	const PropertySpecification& GetPropertySpecification() const;
@@ -74,20 +72,29 @@ protected:
 	/// @param[in] default_value The default value to be used.
 	/// @return The new property definition, ready to have parsers attached.
 	PropertyDefinition& RegisterProperty(const String& property_name, const String& default_value);
-	/// Registers a shorthand property definition.
+	/// Registers a shorthand property definition. Specify a shorthand name of 'decorator' to parse anonymous decorators.
 	/// @param[in] shorthand_name The name to register the new shorthand property under.
 	/// @param[in] properties A comma-separated list of the properties this definition is shorthand for. The order in which they are specified here is the order in which the values will be processed.
 	/// @param[in] type The type of shorthand to declare.
 	/// @param True if all the property names exist, false otherwise.
-	bool RegisterShorthand(const String& shorthand_name, const String& property_names, PropertySpecification::ShorthandType type = PropertySpecification::AUTO);
-
-	// Releases the instancer.
-	virtual void OnReferenceDeactivate();
+	ShorthandId RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type);
 
 private:
 	PropertySpecification properties;
 };
 
+
+class ROCKETCORE_API DecoratorInstancerInterface {
+public:
+	DecoratorInstancerInterface(const StyleSheet& style_sheet) : style_sheet(style_sheet) {}
+
+	/// Get a sprite from any @spritesheet in the style sheet the decorator is being instanced on.
+	const Sprite* GetSprite(const String& name) const;
+
+private:
+	const StyleSheet& style_sheet;
+};
+
 }
 }
 

+ 12 - 27
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;
@@ -197,16 +197,18 @@ public:
 	/// @param[in] name The name of the new property.
 	/// @param[in] property The parsed property to set.
 	/// @return True if the property was set successfully, false otherwise.
-	bool SetProperty(const String& name, const Property& property);
+	bool SetProperty(PropertyId id, const Property& property);
 	/// Removes a local property override on the element; its value will revert to that defined in
 	/// the style sheet.
 	/// @param[in] name The name of the local property definition to remove.
 	void RemoveProperty(const String& name);
+	void RemoveProperty(PropertyId id);
 	/// Returns one of this element's properties. If this element is not defined this property, or a parent cannot
 	/// be found that we can inherit the property from, the default value will be returned.
 	/// @param[in] name The name of the property to fetch the value for.
 	/// @return The value of this property for this element, or NULL if no property exists with the given name.
 	const Property* GetProperty(const String& name);		
+	const Property* GetProperty(PropertyId id);		
 	/// Returns the values of one of this element's properties.		
 	/// @param[in] name The name of the property to get.
 	/// @return The value of this property.
@@ -217,9 +219,10 @@ public:
 	/// @param[in] name The name of the property to fetch the value for.
 	/// @return The value of this property for this element, or NULL if this property has not been explicitly defined for this element.
 	const Property* GetLocalProperty(const String& name);
-	/// Returns the local properties, excluding any properties from local class.
+	const Property* GetLocalProperty(PropertyId id);
+	/// Returns the local style properties, excluding any properties from local class.
 	/// @return The local properties for this element, or NULL if no properties defined
-	const PropertyMap* GetLocalProperties();
+	const PropertyMap& GetLocalStyleProperties();
 	/// Resolves a property with units of length or percentage to 'px'. Percentages are resolved by scaling the base value.
 	/// @param[in] name The property to resolve the value for.
 	/// @param[in] base_value The value that is scaled by the percentage value, if it is a percentage.
@@ -257,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
@@ -320,20 +321,6 @@ public:
 	int GetNumAttributes() const;
 	//@}
 
-	/** @name Decorators
-	 */
-	//@{
-	/// Iterates over all decorators attached to the element. Note that all decorators are iterated
-	/// over, not just active ones.
-	/// @param[inout] index Index to fetch. This is incremented after the fetch.
-	/// @param[out] pseudo_classes The pseudo-classes the decorator required to be active before it renders.
-	/// @param[out] name The name of the decorator at the specified index.
-	/// @param[out] decorator The decorator at the specified index.
-	/// @param[out] decorator_data This element's handle to any data is has stored against the decorator.
-	/// @return True if a decorator was successfully fetched, false if not.
-	bool IterateDecorators(int& index, PseudoClassList& pseudo_classes, String& name, Decorator*& decorator, DecoratorDataHandle& decorator_data);
-	//@}
-
 	/// Gets the outer-most focus element down the tree from this node.
 	/// @return Outer-most focus element.
 	Element* GetFocusLeafNode();
@@ -643,17 +630,16 @@ private:
 	void DirtyStackingContext();
 
 	void DirtyStructure();
-	void DirtyParentStructure();
 	void UpdateStructure();
 
 	void DirtyTransformState(bool perspective_changed, bool transform_changed, bool parent_transform_changed);
 	void UpdateTransformState();
 
 	/// Start an animation, replacing any existing animations of the same property name. If start_value is null, the element's current value is used.
-	ElementAnimationList::iterator StartAnimation(const String & property_name, const Property * start_value, int num_iterations, bool alternate_direction, float delay, bool origin_is_animation_property);
+	ElementAnimationList::iterator StartAnimation(PropertyId property_id, const Property * start_value, int num_iterations, bool alternate_direction, float delay, bool origin_is_animation_property);
 
 	/// Add a key to an animation, extending its duration. If target_value is null, the element's current value is used.
-	bool AddAnimationKeyTime(const String & property_name, const Property * target_value, float time, Tween tween);
+	bool AddAnimationKeyTime(PropertyId property_id, const Property * target_value, float time, Tween tween);
 
 	/// Start a transition of the given property on this element.
 	/// If an animation exists for the property, the call will be ignored. If a transition exists for this property, it will be replaced.
@@ -740,7 +726,6 @@ private:
 	bool stacking_context_dirty;
 
 	bool structure_dirty;
-	bool parent_structure_dirty;
 
 	bool computed_values_are_default_initialized;
 	bool box_dirty;

+ 6 - 5
Include/Rocket/Core/Factory.h

@@ -49,6 +49,8 @@ class FontEffect;
 class FontEffectInstancer;
 class StyleSheet;
 class PropertyDictionary;
+class PropertySpecification;
+class DecoratorInstancerInterface;
 enum class EventId : uint16_t;
 
 /**
@@ -114,12 +116,11 @@ public:
 	/// @param[in] name The name of the decorator the instancer will be called for.
 	/// @param[in] instancer The instancer to call when the decorator name is encountered.
 	/// @return The added instancer if the registration was successful, NULL otherwise.
-	static DecoratorInstancer* RegisterDecoratorInstancer(const String& name, DecoratorInstancer* instancer);
-	/// Attempts to instance a decorator from an instancer registered with the factory.
+	static void RegisterDecoratorInstancer(const String& name, std::unique_ptr<DecoratorInstancer> instancer);
+	/// Retrieves a decorator instancer registered with the factory.
 	/// @param[in] name The name of the desired decorator type.
-	/// @param[in] properties The properties associated with the decorator.
-	/// @return The newly instanced decorator, or NULL if the decorator could not be instanced.
-	static Decorator* InstanceDecorator(const String& name, const PropertyDictionary& properties);
+	/// @return The decorator instancer it it exists, NULL otherwise.
+	static DecoratorInstancer* GetDecoratorInstancer(const String& name);
 
 	/// Registers an instancer that will be used to instance font effects.
 	/// @param[in] name The name of the font effect the instancer will be called for.

+ 2 - 2
Include/Rocket/Core/FontEffectInstancer.h

@@ -80,7 +80,7 @@ protected:
 	/// @param[in] properties A comma-separated list of the properties this definition is shorthand for. The order in which they are specified here is the order in which the values will be processed.
 	/// @param[in] type The type of shorthand to declare.
 	/// @param True if all the property names exist, false otherwise.
-	bool RegisterShorthand(const String& shorthand_name, const String& property_names, PropertySpecification::ShorthandType type = PropertySpecification::AUTO);
+	ShorthandId RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type);
 
 	// Releases the instancer.
 	virtual void OnReferenceDeactivate();
@@ -89,7 +89,7 @@ private:
 	PropertySpecification properties;
 
 	// Properties that define the geometry.
-	std::unordered_set< String > volatile_properties;
+	std::unordered_set< PropertyId > volatile_properties;
 
 	friend class Factory;
 };

+ 117 - 0
Include/Rocket/Core/ID.h

@@ -32,6 +32,123 @@
 namespace Rocket {
 namespace Core {
 
+
+enum class ShorthandId : uint16_t
+{
+	Invalid,
+
+	/*
+	  The following values define the shorthand ids for the main stylesheet specification.
+	  These values must not be used in places that have their own property specification,
+	  such as decorators and font-effects.
+	*/
+	Margin,
+	Padding,
+	BorderWidth,
+	BorderColor,
+	BorderTop,
+	BorderRight,
+	BorderBottom,
+	BorderLeft,
+	Border,
+	Overflow,
+	Background,
+	Font,
+	PerspectiveOrigin,
+	TransformOrigin,
+
+	NumDefinedIds,
+	FirstCustomId = NumDefinedIds
+};
+
+
+enum class PropertyId : uint16_t
+{
+	Invalid,
+
+	/*
+	  The following values define the property ids for the main stylesheet specification.
+	  These values must not be used in places that have their own property specification,
+	  such as decorators and font-effects.
+	*/
+	MarginTop,
+	MarginRight,
+	MarginBottom,
+	MarginLeft,
+	PaddingTop,
+	PaddingRight,
+	PaddingBottom,
+	PaddingLeft,
+	BorderTopWidth,
+	BorderRightWidth,
+	BorderBottomWidth,
+	BorderLeftWidth,
+	BorderTopColor,
+	BorderRightColor,
+	BorderBottomColor,
+	BorderLeftColor,
+	Display,
+	Position,
+	Top,
+	Right,
+	Bottom,
+	Left,
+	Float,
+	Clear,
+	ZIndex,
+	Width,
+	MinWidth,
+	MaxWidth,
+	Height,
+	MinHeight,
+	MaxHeight,
+	LineHeight,
+	VerticalAlign,
+	OverflowX,
+	OverflowY,
+	Clip,
+	Visibility,
+	BackgroundColor,
+	Color,
+	ImageColor,
+	FontFamily,
+	FontCharset,
+	FontStyle,
+	FontWeight,
+	FontSize,
+	TextAlign,
+	TextDecoration,
+	TextTransform,
+	WhiteSpace,
+	Cursor,
+	Drag,
+	TabIndex,
+	ScrollbarMargin,
+
+	Perspective,
+	PerspectiveOriginX,
+	PerspectiveOriginY,
+	Transform,
+	TransformOriginX,
+	TransformOriginY,
+	TransformOriginZ,
+
+	Transition,
+	Animation,
+
+	Opacity,
+	PointerEvents,
+	Focus,
+
+	Decorator,
+	FontEffect,
+
+	NumDefinedIds,
+	FirstCustomId = NumDefinedIds
+};
+
+
+
 enum class EventId : uint16_t 
 {
 	Invalid,

+ 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

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

@@ -77,6 +77,7 @@ public:
 		TRANSFORM = 1 << 17,			// transform; fetch as < TransformRef >, may be empty
 		TRANSITION = 1 << 18,           // transition; fetch as < TransitionList >
 		ANIMATION = 1 << 19,            // animation; fetch as < AnimationList >
+		DECORATOR = 1 << 20,            // decorator; fetch as < DecoratorList >
 
 		LENGTH = PX | DP | PPI_UNIT | EM | REM,
 		LENGTH_PERCENT = LENGTH | PERCENT,

+ 8 - 3
Include/Rocket/Core/PropertyDefinition.h

@@ -41,13 +41,13 @@ namespace Core {
 
 enum class RelativeTarget { None, ContainingBlockWidth, ContainingBlockHeight, FontSize, ParentFontSize, LineHeight };
 
-class ROCKETCORE_API PropertyDefinition
+class ROCKETCORE_API PropertyDefinition final
 {
 public:
-	PropertyDefinition(const String& default_value, bool inherited, bool forces_layout);
+	PropertyDefinition(PropertyId id, const String& default_value, bool inherited, bool forces_layout);
 	PropertyDefinition(const PropertyDefinition &) = delete; 
 	PropertyDefinition& operator=(const PropertyDefinition &) = delete;
-	virtual ~PropertyDefinition();
+	~PropertyDefinition();
 
 	/// Registers a parser to parse values for this definition.
 	/// @param[in] parser_name The name of the parser (default parsers are 'string', 'keyword', 'number' and 'colour').
@@ -81,7 +81,12 @@ public:
 	/// Returns the target for resolving values with percent and possibly number units.
 	RelativeTarget GetRelativeTarget() const;
 
+	/// Return the property id
+	PropertyId GetId() const;
+
 private:
+	PropertyId id;
+
 	Property default_value;
 	bool inherited;
 	bool forces_layout;

+ 4 - 4
Include/Rocket/Core/PropertyDictionary.h

@@ -51,13 +51,13 @@ public:
 	/// Sets a property on the dictionary. Any existing property with a similar name will be overwritten.
 	/// @param[in] name The name of the property to add.
 	/// @param[in] property The value of the new property.
-	void SetProperty(const String& name, const Property& property);
+	void SetProperty(PropertyId id, const Property& property);
 	/// Removes a property from the dictionary, if it exists.
 	/// @param[in] name The name of the property to remove.
-	void RemoveProperty(const String& name);
+	void RemoveProperty(PropertyId id);
 	/// Returns the value of the property with the requested name, if one exists.
 	/// @param[in] name The name of the desired property.
-	const Property* GetProperty(const String& name) const;
+	const Property* GetProperty(PropertyId id) const;
 
 	/// Returns the number of properties in the dictionary.
 	/// @return The number of properties in the dictionary.
@@ -85,7 +85,7 @@ private:
 	// Sets a property on the dictionary and its specificity if there is no name conflict, or its
 	// specificity (given by the parameter, not read from the property itself) is at least equal to
 	// the specificity of the conflicting property.
-	void SetProperty(const String& name, const Rocket::Core::Property& property, int specificity);
+	void SetProperty(PropertyId id, const Rocket::Core::Property& property, int specificity);
 
 	PropertyMap properties;
 };

+ 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<const String&, 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 StringList& 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 StringList* 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<const String&, 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

+ 136 - 26
Include/Rocket/Core/PropertySpecification.h

@@ -35,8 +35,114 @@
 namespace Rocket {
 namespace Core {
 
+class StyleSheetSpecification;
 class PropertyDictionary;
-struct PropertyShorthandDefinition;
+struct ShorthandDefinition;
+
+
+
+template <typename ID>
+class IdNameMap {
+	std::vector<String> name_map;  // IDs are indices into the name_map
+	UnorderedMap<String, ID> reverse_map;
+
+protected:
+	IdNameMap(size_t num_ids_to_reserve) {
+		static_assert((int)ID::Invalid == 0, "Invalid id must be zero");
+		name_map.reserve(num_ids_to_reserve);
+		reverse_map.reserve(num_ids_to_reserve);
+		AddPair(ID::Invalid, "invalid");
+	}
+
+public:
+	void AddPair(ID id, const String& name) {
+		// Should only be used for defined IDs
+		if ((size_t)id >= name_map.size())
+			name_map.resize(1 + (size_t)id);
+		name_map[(size_t)id] = name;
+		bool inserted = reverse_map.emplace(name, id).second;
+		ROCKET_ASSERT(inserted);
+	}
+
+	void AssertAllInserted(ID last_property_inserted) const {
+		ptrdiff_t cnt = std::count_if(name_map.begin(), name_map.end(), [](const String& name) { return !name.empty(); });
+		ROCKET_ASSERT(cnt == (ptrdiff_t)last_property_inserted && reverse_map.size() == (size_t)last_property_inserted);
+	}
+
+	ID GetId(const String& name) const
+	{
+		auto it = reverse_map.find(name);
+		if (it != reverse_map.end())
+			return it->second;
+		return ID::Invalid;
+	}
+	const String& GetName(ID id) const
+	{
+		if (static_cast<size_t>(id) < name_map.size())
+			return name_map[static_cast<size_t>(id)];
+		return name_map[static_cast<size_t>(ID::Invalid)];
+	}
+
+	ID GetOrCreateId(const String& name)
+	{
+		// All predefined properties must be set before adding custom properties here
+		ROCKET_ASSERT(name_map.size() == reverse_map.size());
+
+		ID next_id = static_cast<ID>(name_map.size());
+
+		// Only insert if not already in list
+		auto pair = reverse_map.emplace(name, next_id);
+		const auto& it = pair.first;
+		bool inserted = pair.second;
+
+		if (inserted)
+			name_map.push_back(name);
+
+		// Return the property id that already existed, or the new one if inserted
+		return it->second;
+	}
+};
+
+class PropertyIdNameMap : public IdNameMap<PropertyId> {
+public:
+	PropertyIdNameMap(size_t reserve_num_properties) : IdNameMap(reserve_num_properties) {}
+};
+
+class ShorthandIdNameMap : public IdNameMap<ShorthandId> {
+public:
+	ShorthandIdNameMap(size_t reserve_num_shorthands) : IdNameMap(2 * (size_t)ShorthandId::NumDefinedIds) {}
+};
+
+
+
+enum class ShorthandType
+{
+	// Normal; properties that fail to parse fall-through to the next until they parse correctly, and any
+	// undeclared are not set.
+	FallThrough,
+	// A single failed parse will abort, and any undeclared are replicated from the last declared property.
+	Replicate,
+	// For 'padding', 'margin', etc; up to four properties are expected.
+	Box,
+	// Repeatedly resolves the full value string on each property, whether it is a normal property or another shorthand.
+	Recursive,
+	// Comma-separated list of properties or shorthands, the number of declared values must match the specified.
+	RecursiveCommaSeparated
+};
+
+enum class ShorthandItemType { Invalid, Property, Shorthand };
+struct ShorthandItemId {
+	ShorthandItemId() : type(ShorthandItemType::Invalid) {}
+	ShorthandItemId(PropertyId id) : type(ShorthandItemType::Property), property_id(id) {}
+	ShorthandItemId(ShorthandId id) : type(ShorthandItemType::Shorthand), shorthand_id(id) {}
+
+	ShorthandItemType type;
+	union {
+		PropertyId property_id;
+		ShorthandId shorthand_id;
+	};
+};
+using ShorthandItemIdList = std::vector<ShorthandItemId>;
 
 /**
 	A property specification stores a group of property definitions.
@@ -47,22 +153,7 @@ struct PropertyShorthandDefinition;
 class ROCKETCORE_API PropertySpecification
 {
 public:
-	enum ShorthandType
-	{
-		// Normal; properties that fail to parse fall-through to the next until they parse correctly, and any
-		// undeclared are not set.
-		FALL_THROUGH,
-		// A single failed parse will abort, and any undeclared are replicated from the last declared property.
-		REPLICATE,
-		// For 'padding', 'margin', etc; up four properties are expected.
-		BOX,
-		// Recursively resolves the full value string on each property, whether it is a normal property or another shorthand.
-		RECURSIVE,
-		// BOX if four properties are shorthanded and they end in '-top', '-right', etc, otherwise FALL_THROUGH.
-		AUTO
-	};
-
-	PropertySpecification();
+	PropertySpecification(size_t reserve_num_properties, size_t reserve_num_shorthands);
 	~PropertySpecification();
 
 	/// Registers a property with a new definition.
@@ -70,11 +161,13 @@ public:
 	/// @param[in] default_value The default value to be used for an element if it has no other definition provided.
 	/// @param[in] inherited True if this property is inherited from parent to child, false otherwise.
 	/// @param[in] forces_layout True if this property requires its parent to be reformatted if changed.
+	/// @param[in] id If 'Invalid' then automatically assigns a new id, otherwise assigns the given id.
 	/// @return The new property definition, ready to have parsers attached.
-	PropertyDefinition& RegisterProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout);
+	PropertyDefinition& RegisterProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout, PropertyId id = PropertyId::Invalid);
 	/// Returns a property definition.
-	/// @param[in] property_name The name of the desired property.
+	/// @param[in] id The id of the desired property.
 	/// @return The appropriate property definition if it could be found, NULL otherwise.
+	const PropertyDefinition* GetProperty(PropertyId id) const;
 	const PropertyDefinition* GetProperty(const String& property_name) const;
 
 	/// Returns the list of the names of all registered property definitions.
@@ -89,33 +182,50 @@ public:
 	/// @param[in] shorthand_name The name to register the new shorthand property under.
 	/// @param[in] properties A comma-separated list of the properties this definition is shorthand for. The order in which they are specified here is the order in which the values will be processed.
 	/// @param[in] type The type of shorthand to declare.
+	/// @param[in] id If 'Invalid' then automatically assigns a new id, otherwise assigns the given id.
 	/// @param True if all the property names exist, false otherwise.
-	bool RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type = AUTO);
+	ShorthandId RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type, ShorthandId id = ShorthandId::Invalid);
 	/// Returns a shorthand definition.
 	/// @param[in] shorthand_name The name of the desired shorthand.
 	/// @return The appropriate shorthand definition if it could be found, NULL otherwise.
-	const PropertyShorthandDefinition* GetShorthand(const String& shorthand_name) const;
+	const ShorthandDefinition* GetShorthand(ShorthandId id) const;
+	const ShorthandDefinition* GetShorthand(const String& shorthand_name) const;
+
+	/// Parse declaration by name, whether its a property or shorthand.
+	bool ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value, const String& source_file = "", int source_line_number = 0) const;
+
+	bool ParsePropertyDeclaration(PropertyDictionary& dictionary, PropertyId property_id, const String& property_value, const String& source_file = "", int source_line_number = 0) const;
 
 	/// Parses a property declaration, setting any parsed and validated properties on the given dictionary.
 	/// @param dictionary The property dictionary which will hold all declared properties.
 	/// @param property_name The name of the declared property.
 	/// @param property_value The values the property is being set to.
 	/// @return True if all properties were parsed successfully, false otherwise.
-	bool ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value, const String& source_file = "", int source_line_number = 0) const;
+	bool ParseShorthandDeclaration(PropertyDictionary& dictionary, ShorthandId shorthand_id, const String& property_value, const String& source_file = "", int source_line_number = 0) const;
 	/// Sets all undefined properties in the dictionary to their defaults.
 	/// @param dictionary[in] The dictionary to set the default values on.
 	void SetPropertyDefaults(PropertyDictionary& dictionary) const;
 
+	/// Returns the properties of dictionary converted to a string.
+	String PropertiesToString(const PropertyDictionary& dictionary) const;
+
 private:
-	typedef UnorderedMap< String, PropertyDefinition* > PropertyMap;
-	typedef UnorderedMap< String, PropertyShorthandDefinition* > ShorthandMap;
+	typedef std::vector< PropertyDefinition* > Properties;
+	typedef std::vector< ShorthandDefinition* > Shorthands;
+
+	Properties properties;
+	Shorthands shorthands;
 
-	PropertyMap properties;
-	ShorthandMap shorthands;
+	PropertyIdNameMap property_map;
+	ShorthandIdNameMap shorthand_map;
+
+	// todo: Do we really need these?
 	PropertyNameList property_names;
 	PropertyNameList inherited_property_names;
 
 	bool ParsePropertyValues(StringList& values_list, const String& values, bool split_values) const;
+
+	friend class StyleSheetSpecification;
 };
 
 }

+ 95 - 0
Include/Rocket/Core/Spritesheet.h

@@ -0,0 +1,95 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2019 Michael R. P. Ragazzon
+ *
+ * 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 ROCKETSPRITESHEET_H
+#define ROCKETSPRITESHEET_H
+
+#include "Types.h"
+#include "Texture.h"
+
+namespace Rocket {
+namespace Core {
+
+struct Spritesheet;
+
+
+struct Rectangle {
+	Rectangle(float x = 0, float y = 0, float width = 0, float height = 0) : x(x), y(y), width(width), height(height) {}
+	float x, y, width, height;
+};
+
+struct Sprite {
+	Rectangle rectangle; // in 'px' units
+	const Spritesheet* sprite_sheet;
+};
+using SpriteMap = UnorderedMap<String, Sprite>; // key: sprite name (as given in @spritesheet)
+
+
+/**
+	Spritesheet holds a list of sprite names given in the @spritesheet at-rule in RCSS.
+ */
+struct Spritesheet {
+	String name;
+	String image_source;
+	String definition_source;
+	int definition_line_number;
+	Texture texture;
+	StringList sprite_names;
+
+	Spritesheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, const Texture& texture)
+		: name(name), image_source(image_source), definition_source(definition_source), definition_line_number(definition_line_number), texture(texture) {}
+};
+
+using SpritesheetMap = SmallUnorderedMap<String, std::shared_ptr<Spritesheet>>; // key: spritesheet name (as given in @spritesheet)
+using SpriteDefinitionList = std::vector<std::pair<String, Rectangle>>; // Sprite name and rectangle
+
+
+/**
+	SpritesheetList holds all the spritesheets and sprites given in a style sheet.
+ */
+class SpritesheetList {
+public:
+	/// Adds a new sprite sheet to the list and inserts all sprites with unique names into the global list.
+	bool AddSpriteSheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, const SpriteDefinitionList& sprite_definitions);
+
+	/// Get a sprite from its name if it exists.
+	/// Note: The pointer is invalidated whenever another sprite is added. Do not store it around.
+	const Sprite* GetSprite(const String& name) const;
+
+	/// Merge 'other' into this.
+	void Merge(const SpritesheetList& other);
+
+private:
+	SpritesheetMap spritesheet_map;
+	SpriteMap sprite_map;
+};
+
+
+}
+}
+
+#endif

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

@@ -50,6 +50,7 @@ ROCKETCORE_API String CreateString(size_t max_size, const char* format, ...);
 
 ROCKETCORE_API String ToLower(const String& string);
 ROCKETCORE_API String Replace(String subject, const String& search, const String& replace);
+ROCKETCORE_API String Replace(String subject, char search, char replace);
 
 ROCKETCORE_API WString ToWideString(const String& str);
 ROCKETCORE_API String ToUTF8(const WString& wstr);

+ 7 - 0
Include/Rocket/Core/StringUtilities.h

@@ -49,6 +49,13 @@ public:
 	/// @param[in] string String to expand.
 	/// @param[in] delimiter Delimiter found between entries in the string list.
 	static void ExpandString(StringList& string_list, const String& string, const char delimiter = ',');
+	/// Expands character-delimited list of values with custom quote characters.
+	/// @param[out] string_list Resulting list of values.
+	/// @param[in] string String to expand.
+	/// @param[in] delimiter Delimiter found between entries in the string list.
+	/// @param[in] quote_character Begin quote
+	/// @param[in] unquote_character End quote
+	static void ExpandString(StringList& string_list, const String& string, const char delimiter, char quote_character, char unquote_character);
 	/// Joins a list of string values into a single string separated by a character delimiter.
 	/// @param[out] string Resulting concatenated string.
 	/// @param[in] string_list Input list of string values.

+ 34 - 8
Include/Rocket/Core/StyleSheet.h

@@ -28,10 +28,10 @@
 #ifndef ROCKETCORESTYLESHEET_H
 #define ROCKETCORESTYLESHEET_H
 
-#include "Dictionary.h"
 #include "ReferenceCountable.h"
-#include <set>
 #include "PropertyDictionary.h"
+#include "Spritesheet.h"
+#include <set>
 
 namespace Rocket {
 namespace Core {
@@ -39,16 +39,28 @@ namespace Core {
 class Element;
 class ElementDefinition;
 class StyleSheetNode;
+class Decorator;
+class SpritesheetList;
+struct Sprite;
+struct Spritesheet;
 
 struct KeyframeBlock {
 	float normalized_time;  // [0, 1]
 	PropertyDictionary properties;
 };
 struct Keyframes {
-	std::vector<String> property_names;
+	std::vector<PropertyId> property_ids;
 	std::vector<KeyframeBlock> blocks;
 };
-typedef UnorderedMap<String, Keyframes> KeyframesMap;
+using KeyframesMap = UnorderedMap<String, Keyframes>;
+
+struct DecoratorSpecification {
+	String decorator_type;
+	PropertyDictionary properties;
+	std::shared_ptr<Decorator> decorator;
+};
+using DecoratorSpecificationMap = UnorderedMap<String, DecoratorSpecification>;
+
 
 /**
 	StyleSheet maintains a single stylesheet definition. A stylesheet can be combined with another stylesheet to create
@@ -71,12 +83,22 @@ public:
 
 	/// Combines this style sheet with another one, producing a new sheet.
 	StyleSheet* CombineStyleSheet(const StyleSheet* sheet) const;
-	/// Builds the node index for a combined style sheet.
-	void BuildNodeIndex();
+	/// Builds the node index for a combined style sheet, and optimizes some properties for faster retrieval.
+	/// Specifically, converts all decorator properties from strings to instanced decorator lists.
+	void BuildNodeIndexAndOptimizeProperties();
 
 	/// Returns the Keyframes of the given name, or null if it does not exist.
 	Keyframes* GetKeyframes(const String& name);
 
+	/// Returns the Decorator of the given name, or null if it does not exist.
+	std::shared_ptr<Decorator> GetDecorator(const String& name) const;
+
+	/// Parses the decorator property from a string and returns a list of instanced decorators.
+	DecoratorList InstanceDecoratorsFromString(const String& decorator_string_value, const String& source_file, int source_line_number) const;
+
+	/// Get sprite located in any spritesheet within this stylesheet.
+	const Sprite* GetSprite(const String& name) const;
+
 	/// Returns the compiled element definition for a given element hierarchy. A reference count will be added for the
 	/// caller, so another should not be added. The definition should be released by removing the reference count.
 	ElementDefinition* GetElementDefinition(const Element* element) const;
@@ -99,14 +121,18 @@ private:
 	// Name of every @keyframes mapped to their keys
 	KeyframesMap keyframes;
 
+	// Name of every @decorator mapped to their specification
+	DecoratorSpecificationMap decorator_map;
+
+	// Name of every @spritesheet and underlying sprites mapped to their values
+	SpritesheetList spritesheet_list;
+
 	// Map of only nodes with actual style information.
 	NodeIndex styled_node_index;
 	// Map of every node, even empty, un-styled, nodes.
 	NodeIndex complete_node_index;
 
 	typedef UnorderedMap< size_t, ElementDefinition* > ElementDefinitionCache;
-	// Index of element addresses to element definitions.
-	mutable ElementDefinitionCache address_cache;
 	// Index of node sets to element definitions.
 	mutable ElementDefinitionCache node_cache;
 };

+ 20 - 4
Include/Rocket/Core/StyleSheetSpecification.h

@@ -36,6 +36,7 @@ namespace Rocket {
 namespace Core {
 
 class PropertyParser;
+class DirtyPropertyList;
 
 /**
 	@author Peter Curry
@@ -60,7 +61,7 @@ public:
 	/// @return The parser registered under the given name, or NULL if no such parser exists.
 	static PropertyParser* GetParser(const String& parser_name);
 
-	/// Registers a property with a new definition.
+	/// Registers a custom property with a new definition.
 	/// @param[in] property_name The name to register the new property under.
 	/// @param[in] default_value The default value to be used for an element if it has no other definition provided.
 	/// @param[in] inherited True if this property is inherited from parent to child, false otherwise.
@@ -71,6 +72,7 @@ public:
 	/// @param[in] property_name The name of the desired property.
 	/// @return The appropriate property definition if it could be found, NULL otherwise.
 	static const PropertyDefinition* GetProperty(const String& property_name);
+	static const PropertyDefinition* GetProperty(PropertyId id);
 
 	/// Returns the list of the names of all registered property definitions.
 	/// @return The list with stored property names.
@@ -80,16 +82,17 @@ public:
 	/// @return The list with stored property names.
 	static const PropertyNameList & GetRegisteredInheritedProperties();
 
-	/// Registers a shorthand property definition.
+	/// Registers a custom shorthand property definition.
 	/// @param[in] shorthand_name The name to register the new shorthand property under.
 	/// @param[in] properties A comma-separated list of the properties this definition is shorthand for. The order in which they are specified here is the order in which the values will be processed.
 	/// @param[in] type The type of shorthand to declare.
 	/// @param True if all the property names exist, false otherwise.
-	static bool RegisterShorthand(const String& shorthand_name, const String& property_names, PropertySpecification::ShorthandType type = PropertySpecification::AUTO);
+	static ShorthandId RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type);
 	/// Returns a shorthand definition.
 	/// @param[in] shorthand_name The name of the desired shorthand.
 	/// @return The appropriate shorthand definition if it could be found, NULL otherwise.
-	static const PropertyShorthandDefinition* GetShorthand(const String& shorthand_name);
+	static const ShorthandDefinition* GetShorthand(const String& shorthand_name);
+	static const ShorthandDefinition* GetShorthand(ShorthandId id);
 
 	/// Parses a property declaration, setting any parsed and validated properties on the given dictionary.
 	/// @param[in] dictionary The property dictionary which will hold all declared properties.
@@ -100,10 +103,23 @@ public:
 	/// @return True if all properties were parsed successfully, false otherwise.
 	static bool ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value, const String& source_file = "", int source_line_number = 0);
 
+	static PropertyId GetPropertyId(const String& property_name);
+	static ShorthandId GetShorthandId(const String& shorthand_name);
+	static const String& GetPropertyName(PropertyId id);
+	static const String& GetShorthandName(ShorthandId id);
+	static const DirtyPropertyList& GetRegisteredInheritedPropertyBitList();
+
+	static std::vector<PropertyId> GetShorthandUnderlyingProperties(ShorthandId id);
+
+	static const PropertySpecification& GetPropertySpecification();
+
 private:
 	StyleSheetSpecification();
 	~StyleSheetSpecification();
 
+	PropertyDefinition& RegisterProperty(PropertyId id, const String& property_name, const String& default_value, bool inherited, bool forces_layout = false);
+	ShorthandId RegisterShorthand(ShorthandId id, const String& shorthand_name, const String& property_names, ShorthandType type);
+
 	// Registers Rocket's default parsers.
 	void RegisterDefaultParsers();
 	// Registers Rocket's default style properties.

+ 6 - 0
Include/Rocket/Core/Texture.h

@@ -73,6 +73,12 @@ public:
 	/// Releases this texture's resource (if any), and sets it to another texture's resource.
 	const Texture& operator=(const Texture&);
 
+	/// Returns true if the texture points to the same underlying resource.
+	bool operator==(const Texture&) const;
+
+	/// Returns true if the underlying resource is set.
+	operator bool() const;
+
 private:
 	TextureResource* resource;
 };

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

@@ -81,7 +81,6 @@ private:
 };
 
 
-ROCKETCORE_API String ToString(const Transform& transform);
 
 }
 }

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

@@ -29,7 +29,6 @@
 #define ROCKETCORETYPECONVERTER_H
 
 #include "Types.h"
-#include "Animation.h"
 #include "Log.h"
 #include "Stream.h"
 #include "StringUtilities.h"
@@ -56,6 +55,47 @@ public:
 	static bool Convert(const SourceType& src, DestType& dest);
 };
 
+
+// Some more complex types are defined in cpp-file
+
+template<> class TypeConverter< TransformRef, TransformRef > {
+public:
+	ROCKETCORE_API static bool Convert(const TransformRef& src, TransformRef& dest);
+};
+
+template<> class TypeConverter< TransformRef, String > {
+public:
+	ROCKETCORE_API static bool Convert(const TransformRef& src, String& dest);
+};
+
+template<> class TypeConverter< TransitionList, TransitionList > {
+public:
+	ROCKETCORE_API static bool Convert(const TransitionList& src, TransitionList& dest);
+};
+template<> class TypeConverter< TransitionList, String > {
+public:
+	ROCKETCORE_API static bool Convert(const TransitionList& src, String& dest);
+};
+
+template<> class TypeConverter< AnimationList, AnimationList > {
+public:
+	ROCKETCORE_API static bool Convert(const AnimationList& src, AnimationList& dest);
+};
+template<> class TypeConverter< AnimationList, String > {
+public:
+	ROCKETCORE_API static bool Convert(const AnimationList& src, String& dest);
+};
+
+template<> class TypeConverter< DecoratorList, DecoratorList > {
+public:
+	ROCKETCORE_API static bool Convert(const DecoratorList& src, DecoratorList& dest);
+};
+template<> class TypeConverter< DecoratorList, String > {
+public:
+	ROCKETCORE_API static bool Convert(const DecoratorList& src, String& dest);
+};
+
+
 }
 }
 

+ 0 - 67
Include/Rocket/Core/TypeConverter.inl

@@ -114,9 +114,6 @@ PASS_THROUGH(Vector4f);
 PASS_THROUGH(Colourf);
 PASS_THROUGH(Colourb);
 PASS_THROUGH(String);
-PASS_THROUGH(TransformRef);
-PASS_THROUGH(TransitionList);
-PASS_THROUGH(AnimationList);
 
 // Pointer types need to be typedef'd
 class ScriptInterface;
@@ -354,70 +351,6 @@ public:
 };
 
 
-ROCKETCORE_API String ToString(const Transform& transform);
-
-template<>
-class TypeConverter< TransformRef, String >
-{
-public:
-	static bool Convert(const TransformRef& src, String& dest)
-	{
-		if (src) dest = ToString(*src);
-		else dest = "none";
-		return true;
-	}
-};
-
-template<>
-class TypeConverter< TransitionList, String >
-{
-public:
-	static bool Convert(const TransitionList& src, String& dest)
-	{
-		if (src.none)
-		{
-			dest = "none";
-			return true;
-		}
-		String tmp;
-		for (size_t i = 0; i < src.transitions.size(); i++)
-		{
-			const Transition& t = src.transitions[i];
-			dest += t.name + " ";
-			dest += t.tween.to_string() + " ";
-			if (TypeConverter< float, String >::Convert(t.duration, tmp)) dest += tmp + "s ";
-			if (t.delay > 0.0f && TypeConverter< float, String >::Convert(t.delay, tmp)) dest += tmp + "s ";
-			if (t.reverse_adjustment_factor > 0.0f && TypeConverter< float, String >::Convert(t.delay, tmp)) dest += tmp;
-			if (dest.size() > 0) dest.resize(dest.size() - 1);
-			if (i != src.transitions.size() - 1) dest += ", ";
-		}
-		return true;
-	}
-};
-
-template<>
-class TypeConverter< AnimationList, String >
-{
-public:
-	static bool Convert(const AnimationList& src, String& dest)
-	{
-		String tmp;
-		for (size_t i = 0; i < src.size(); i++)
-		{
-			const Animation& a = src[i];
-			if (TypeConverter< float, String >::Convert(a.duration, tmp)) dest += tmp + "s ";
-			dest += a.tween.to_string() + " ";
-			if (a.delay > 0.0f && TypeConverter< float, String >::Convert(a.delay, tmp)) dest += tmp + "s ";
-			if (a.alternate) dest += "alternate ";
-			if (a.paused) dest += "paused ";
-			if (a.num_iterations == -1) dest += "infinite ";
-			else if(TypeConverter< int, String >::Convert(a.num_iterations, tmp)) dest += tmp + " ";
-			dest += a.name;
-			if (i != src.size() - 1) dest += ", ";
-		}
-		return true;
-	}
-};
 
 template< typename SourceType, typename InternalType, int count >
 class TypeConverterVectorString

+ 19 - 12
Include/Rocket/Core/Types.h

@@ -48,6 +48,10 @@
 #include "Platform.h"
 #include "Debug.h"
 
+#ifdef ROCKET_DEBUG
+#include <unordered_map>
+#endif
+
 namespace Rocket {
 namespace Core {
 
@@ -97,6 +101,10 @@ class ElementAnimation;
 class Property;
 class Variant;
 class Transform;
+class Decorator;
+struct Animation;
+struct Rectangle;
+enum class PropertyId : uint16_t;
 
 // Types for external interfaces.
 typedef uintptr_t FileHandle;
@@ -105,24 +113,29 @@ typedef uintptr_t CompiledGeometryHandle;
 typedef uintptr_t DecoratorDataHandle;
 
 // Common containers
+#ifdef ROCKET_DEBUG
+template < typename Key, typename Value>
+using UnorderedMap = std::unordered_map< Key, Value >;
+#else
 template < typename Key, typename Value>
 using UnorderedMap = robin_hood::unordered_flat_map< Key, Value >;
+#endif
 template < typename Key, typename Value>
 using SmallUnorderedMap = chobo::flat_map< Key, Value >;
 template < typename T >
 using SmallOrderedSet = chobo::flat_set< T >;
 template < typename T >
 using SmallUnorderedSet = chobo::flat_set< T >;
-// Note: Right now ordered and unordered set use the same container, but we may
+// Note: Right now small ordered and unordered set use the same container, but we may
 // want to change this later so use ordered when a sorted container is needed.
 
 // Container types for some common lists
 typedef std::vector< Element* > ElementList;
-typedef std::vector< String > PseudoClassList;
 typedef std::vector< ElementAnimation > ElementAnimationList;
+typedef SmallUnorderedSet< String > PseudoClassList;
 typedef SmallUnorderedSet< String > AttributeNameList;
-typedef SmallOrderedSet< String > PropertyNameList;
-typedef UnorderedMap< String, Property > PropertyMap;
+typedef SmallOrderedSet< PropertyId > PropertyNameList;
+typedef UnorderedMap< PropertyId, Property > PropertyMap;
 typedef SmallUnorderedMap< String, Variant > Dictionary;
 typedef Dictionary ElementAttributes;
 
@@ -132,14 +145,8 @@ typedef std::shared_ptr< Transform > TransformRef;
 struct Transition;
 struct TransitionList;
 
-// Pseudo class properties
-// Defines for the optimised version of the pseudo-class properties (note the difference from the
-// PseudoClassPropertyMap defined in StyleSheetNode.h ... bit clumsy). Here the properties are stored as a list
-// of definitions against each property name in specificity-order, along with the pseudo-class requirements for each
-// one. This makes it much more straight-forward to query at run-time.
-typedef std::pair< StringList, Property > PseudoClassProperty;
-typedef std::vector< PseudoClassProperty > PseudoClassPropertyList;
-typedef SmallUnorderedMap< String, PseudoClassPropertyList > PseudoClassPropertyDictionary;
+using DecoratorList = std::vector<std::shared_ptr<Decorator>>;
+using AnimationList = std::vector<Animation>;
 
 }
 }

+ 2 - 0
Include/Rocket/Core/Variant.h

@@ -78,6 +78,7 @@ public:
 		TRANSFORMREF = 't',
 		TRANSITIONLIST = 'T',
 		ANIMATIONLIST = 'A',
+		DECORATORLIST = 'D',
 		VOIDPTR = '*',			
 	};
 
@@ -134,6 +135,7 @@ private:
 	void Set(const TransformRef& value);
 	void Set(const TransitionList& value);
 	void Set(const AnimationList& value);
+	void Set(const DecoratorList& value);
 	void Set(const Colourf& value);
 	void Set(const Colourb& value);
 	void Set(ScriptInterface* value);

+ 4 - 0
Include/Rocket/Core/Variant.inl

@@ -102,6 +102,10 @@ bool Variant::GetInto(T& value) const
 		return TypeConverter< AnimationList, T >::Convert(*(AnimationList*)data, value);
 		break;
 
+	case DECORATORLIST:
+		return TypeConverter< DecoratorList, T >::Convert(*(DecoratorList*)data, value);
+		break;
+
 	case COLOURF:
 		return TypeConverter< Colourf, T >::Convert(*(Colourf*)data, value);
 		break;

+ 16 - 0
Include/Rocket/Core/Vector2.h

@@ -89,10 +89,18 @@ class Vector2
 		/// @param[in] rhs The scalar value to multiply by.
 		/// @return The result of the scale.
 		inline Vector2 operator*(Type rhs) const;
+		/// Returns the result of element-wise multiplication.
+		/// @param[in] rhs The vector to multiply by.
+		/// @return The result of the multiplication.
+		inline Vector2 operator*(const Vector2& rhs) const;
 		/// Returns the result of dividing this vector by a scalar.
 		/// @param[in] rhs The scalar value to divide by.
 		/// @return The result of the scale.
 		inline Vector2 operator/(Type rhs) const;
+		/// Returns the result of element-wise division.
+		/// @param[in] rhs The vector to divide by.
+		/// @return The result of the division.
+		inline Vector2 operator/(const Vector2& rhs) const;
 
 		/// Adds another vector to this in-place.
 		/// @param[in] rhs The vector to add.
@@ -106,10 +114,18 @@ class Vector2
 		/// @param[in] rhs The value to scale this vector's components by.
 		/// @return This vector, post-operation.
 		inline Vector2& operator*=(const Type& rhs);
+		/// Element-wise multiplication in-place.
+		/// @param[in] rhs The vector to multiply.
+		/// @return This vector, post-operation.
+		inline Vector2& operator*=(const Vector2& rhs);
 		/// Scales this vector in-place by the inverse of a value.
 		/// @param[in] rhs The value to divide this vector's components by.
 		/// @return This vector, post-operation.
 		inline Vector2& operator/=(const Type& rhs);
+		/// Element-wise division in-place.
+		/// @param[in] rhs The vector to divide by.
+		/// @return This vector, post-operation.
+		inline Vector2& operator/=(const Vector2& rhs);
 
 		/// Equality operator.
 		/// @param[in] rhs The vector to compare this against.

+ 29 - 0
Include/Rocket/Core/Vector2.inl

@@ -136,6 +136,12 @@ Vector2< Type > Vector2< Type >::operator*(Type rhs) const
 	return Vector2(x * rhs, y * rhs);
 }
 
+template<typename Type>
+Vector2< Type > Vector2<Type>::operator*(const Vector2& rhs) const
+{
+	return Vector2(x * rhs.x, y * rhs.y);
+}
+
 // Returns the result of dividing this vector by a scalar.
 template < typename Type >
 Vector2< Type > Vector2< Type >::operator/(Type rhs) const
@@ -143,6 +149,12 @@ Vector2< Type > Vector2< Type >::operator/(Type rhs) const
 	return Vector2(x / rhs, y / rhs);
 }
 
+template<typename Type>
+Vector2< Type > Vector2<Type>::operator/(const Vector2& rhs) const
+{
+	return Vector2(x / rhs.x, y / rhs.y);
+}
+
 // Adds another vector to this in-place.
 template < typename Type >
 Vector2< Type >& Vector2< Type >::operator+=(const Vector2 & rhs)
@@ -173,6 +185,15 @@ Vector2< Type >& Vector2< Type >::operator*=(const Type & rhs)
 	return *this;
 }
 
+template<typename Type>
+Vector2< Type >& Vector2<Type>::operator*=(const Vector2& rhs)
+{
+	x *= rhs.x;
+	y *= rhs.y;
+
+	return *this;
+}
+
 // Scales this vector in-place by the inverse of a value.
 template < typename Type >
 Vector2< Type >& Vector2< Type >::operator/=(const Type & rhs)
@@ -183,6 +204,14 @@ Vector2< Type >& Vector2< Type >::operator/=(const Type & rhs)
 	return *this;
 }
 
+template<typename Type>
+Vector2< Type >& Vector2<Type>::operator/=(const Vector2& rhs)
+{
+	x /= rhs.x;
+	y /= rhs.y;
+	return *this;
+}
+
 // Equality operator.
 template < typename Type >
 bool Vector2< Type >::operator==(const Vector2 & rhs) const

+ 1 - 2
Samples/assets/cursor.rml

@@ -8,8 +8,7 @@
 				height: 19px;
 				
 				<!-- Add a simple image decorator onto the body element. -->
-				cursor-decorator: image;
-				cursor-image: invader.tga 56px 212px 68px 231px;
+				decorator: image( invader.tga 56px 212px 68px 231px );
 			}
 		</style>
 	</head>

+ 185 - 108
Samples/assets/invader.rcss

@@ -1,3 +1,110 @@
+@spritesheet theme 
+{
+	src: invader.tga;
+	
+	/**
+	   The following specifies a list of sprite names and associated rectangles into the image given above.
+	   Any sprite given here can be specified in a decorator. Their names must be globally unique.
+	   Rectangles are specified as: x y width height.
+	*/
+	title-bar-l: 147px 0px 82px 85px;
+	title-bar-c: 229px 0px  1px 85px;
+	title-bar-r: 231px 0px 15px 85px;
+	
+	/* huditems are vertically flipped titlebars */
+	huditem-l: 147px 55px 82px -55px;
+	huditem-c: 229px 55px  1px -55px;
+	huditem-r: 231px 55px 15px -55px;
+	
+	icon-help:    128px 152px 51px 39px;
+	icon-invader: 179px 152px 51px 39px;
+	icon-game:    230px 152px 51px 39px;
+	icon-hiscore: 281px 152px 51px 39px;
+	icon-waves:   332px 152px 51px 39px;
+	icon-flag:    332px 191px 51px 39px;
+	icon-lives:   383px 152px 51px 39px;
+	icon-score:   434px 152px 51px 39px;
+	
+	window-tl: 0px 0px 133px 140px;
+	window-t:  134px 0px 1px 140px;
+	window-tr: 136px 0px 10px 140px;
+	window-l:  0px 139px 10px 1px;
+	window-c:  11px 139px 1px 1px;
+	window-r:  10px 139px -10px 1px; /* mirrored left */
+	window-bl: 0px 140px 11px 11px;
+	window-b:  11px 140px 1px 11px;
+	window-br: 136px 140px 10px 11px;
+	
+	button: 247px 0px 159px 45px;
+	button-hover:  247px 45px 159px 45px;
+	button-active: 247px 90px 159px 45px;
+	
+	text-l: 162px 192px 14px 31px;
+	text-c: 176px 192px 1px 31px;
+	
+	selectbox-tl: 281px 275px 11px 9px;
+	selectbox-t:  292px 275px 1px 9px;
+	selectbox-tr: 294px 275px 11px 9px;
+	selectbox-l:  281px 283px 11px 1px;
+	selectbox-c:  292px 283px 1px 1px;
+	selectbox-bl: 281px 285px 11px 11px;
+	selectbox-b:  292px 285px 1px 11px;
+	selectbox-br: 294px 285px 11px 11px;
+	
+	selectvalue: 162px 192px 145px 37px;
+	selectvalue-hover: 162px 230px 145px 37px;
+	selectarrow: 307px 192px 30px 37px;
+	selectarrow-hover: 307px 230px 30px 37px;
+	selectarrow-active: 307px 268px 30px 37px;
+	
+	radio: 407px 0px 30px 30px;
+	radio-hover: 437px 0px 30px 30px;
+	radio-active: 467px 0px 30px 30px;
+	radio-checked: 407px 30px 30px 30px;
+	radio-checked-hover: 437px 30px 30px 30px;
+	radio-checked-active: 467px 30px 30px 30px;
+	
+	checkbox: 407px 60px 30px 30px;
+	checkbox-hover: 437px 60px 30px 30px;
+	checkbox-active: 467px 60px 30px 30px;
+	checkbox-checked: 407px 90px 30px 30px;
+	checkbox-checked-hover: 437px 90px 30px 30px;
+	checkbox-checked-active: 467px 90px 30px 30px;
+	
+	datagridheader-l: 127px 192px 16px 31px;
+	datagridheader-c: 143px 192px 2px 31px;
+	datagridheader-r: 145px 192px 15px 31px;
+	
+	datagridexpand: 3px 232px 17px 17px;
+	datagridexpand-hover: 21px 232px 17px 17px;
+	datagridexpand-active: 39px 232px 17px 17px;
+	datagridexpand-collapsed: 3px 250px 17px 17px;
+	datagridexpand-collapsed-hover: 21px 250px 17px 17px;
+	datagridexpand-collapsed-active: 39px 250px 17px 17px;
+	
+	slidertrack-t: 70px 199px 27px 2px;
+	slidertrack-c: 70px 201px 27px 1px;
+	slidertrack-b: 70px 202px 27px 2px;
+	
+	sliderbar-t:         56px 152px 23px 23px;
+	sliderbar-c:         56px 175px 23px 1px;
+	sliderbar-b:         56px 176px 23px 22px;
+	sliderbar-hover-t:   80px 152px 23px 23px;
+	sliderbar-hover-c:   80px 175px 23px 1px;
+	sliderbar-hover-b:   80px 176px 23px 22px;
+	sliderbar-active-t: 104px 152px 23px 23px;
+	sliderbar-active-c: 104px 175px 23px 1px;
+	sliderbar-active-b: 104px 176px 23px 22px;
+	 
+	sliderarrowdec: 0px 152px 27px 24px;
+	sliderarrowdec-hover: 0px 177px 27px 24px;
+	sliderarrowdec-active: 0px 202px 27px 24px;
+	
+	sliderarrowinc: 28px 152px 27px 24px;
+	sliderarrowinc-hover: 28px 177px 27px 24px;
+	sliderarrowinc-active: 28px 202px 27px 24px;
+}
+
 body
 {
 	font-family: Delicious;
@@ -19,8 +126,6 @@ body.window
 	max-height: 700px;
 }
 
-
-
 div#title_bar
 {
 	z-index: 1;
@@ -40,17 +145,15 @@ div#title_bar div#icon
 	
 	width: 51px;
 	height: 39px;
-	
-	icon-decorator: image;
-	icon-image-src: invader.tga;
 }
 
+
 div#title_bar span
 {
 	padding-left: 85px;
 	padding-right: 25px;
 	padding-top: 17px;
-	padding-bottom: 48px;
+	padding-bottom: 51px;
 
 	font-size: 22px;
 	font-weight: bold;
@@ -59,28 +162,19 @@ div#title_bar span
 	outline-width: 1px;
 	outline-color: black;
 
-	background-decorator: tiled-horizontal;
-	background-left-image: invader.tga 147px 0px 229px 85px;
-	background-center-image: invader.tga stretch 229px 0px 230px 85px;
-	background-right-image: invader.tga 231px 0px 246px 85px;
+	decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
 }
 
-
-
 div#window
 {
 	width: auto;
 	padding: 10px 15px;
-
-	background-decorator: tiled-box;
-	background-top-left-image: invader.tga 0px 0px 133px 140px;
-	background-top-right-image: invader.tga 136px 0px 146px 140px;
-	background-top-image: invader.tga stretch 134px 0px 135px 140px;
-	background-bottom-left-image: invader.tga 0px 140px 11px 151px;
-	background-bottom-right-image: invader.tga 136px 140px 146px 151px;
-	background-bottom-image: invader.tga stretch 11px 140px 12px 151px;
-	background-left-image: invader.tga stretch 0px 139px 10px 140px;
-	background-center-image: invader.tga stretch 11px 139px 12px 140px;
+	
+	decorator: tiled-box(
+		window-tl, window-t, window-tr, 
+		window-l, window-c, window-r,
+		window-bl, window-b, window-br
+	);
 }
 
 div#content
@@ -148,8 +242,7 @@ input.submit
 	text-align: center;
 	tab-index: auto;
 
-	background-decorator: image;
-	background-image: invader.tga 247px 0px 406px 45px;
+	decorator: image(button);
 }
 
 button:focus,
@@ -165,18 +258,18 @@ input.submit:focus
 button:hover,
 input.submit:hover
 {
-	background-image-t: 45px 90px;
+	decorator: image(button-hover);
 }
 
 button:active,
 input.submit:active
 {
-	background-image-t: 90px 135px;
+	decorator: image(button-active);
 }
 
 input.submit:disabled
 {
-	background-image-t: 0px 45px;
+	decorator: image(button);
 	image-color: rgba(50, 150, 150, 120);
 	cursor: unavailable;
 }
@@ -188,9 +281,7 @@ input.text
 	height: 31px;
 	padding: 10px 10px 0px;
 
-	background-decorator: tiled-horizontal;
-	background-left-image: invader.tga 162px 192px 176px 223px;
-	background-center-image: invader.tga stretch 176px 192px 177px 223px;
+	decorator: tiled-horizontal( text-l, text-c, auto ); /* Right becomes mirrored left */
 }
 
 input.text,
@@ -214,7 +305,7 @@ datagrid input.text
 
 	font-size: 15px;
 	
-	background-decorator: none;
+	decorator: none;
 }
 
 
@@ -235,14 +326,13 @@ dataselect selectvalue
 	height: 28px;
 	padding: 9px 10px 0px 10px;
 
-	background-decorator: image;
-	background-image: invader.tga 162px 192px 307px 229px;
+	decorator: image( selectvalue  );
 }
 
 select selectvalue:hover,
 dataselect selectvalue:hover
 {
-	background-image-t: 230px 267px;
+	decorator: image( selectvalue-hover );
 }
 
 select selectarrow,
@@ -251,14 +341,13 @@ dataselect selectarrow
 	width: 30px;
 	height: 37px;
 	
-	icon-decorator: image;
-	icon-image: invader.tga 307px 192px 337px 229px;
+	decorator: image( selectarrow );
 }
 
 select selectarrow:hover,
 dataselect selectarrow:hover
 {
-	icon-image-t: 230px 267px;
+	decorator: image( selectarrow-hover );
 }
 
 select selectarrow:active,
@@ -266,7 +355,7 @@ select selectarrow:checked,
 dataselect selectarrow:active,
 dataselect selectarrow:checked
 {
-	icon-image-t: 268px 305px;
+	decorator: image( selectarrow-active );
 }
 
 select selectbox,
@@ -282,15 +371,11 @@ select selectbox,
 dataselect selectbox,
 datagrid datagridbody
 {
-	background-decorator: tiled-box;
-	background-top-left-image: invader.tga 281px 275px 292px 284px;
-	background-top-right-image: invader.tga 294px 275px 305px 284px;
-	background-top-image: invader.tga stretch 292px 275px 293px 284px;
-	background-bottom-left-image: invader.tga 281px 285px 292px 296px;
-	background-bottom-right-image: invader.tga 294px 285px 305px 296px;
-	background-bottom-image: invader.tga stretch 292px 285px 293px 296px;
-	background-left-image: invader.tga stretch 281px 283px 292px 284px;
-	background-center-image: invader.tga stretch 292px 283px 293px 284px;
+	decorator: tiled-box(
+		selectbox-tl, selectbox-t, selectbox-tr, 
+		selectbox-l, selectbox-c, auto,  /* auto mirrors left */
+		selectbox-bl, selectbox-b, selectbox-br
+	);
 }
 
 select selectbox option,
@@ -326,82 +411,71 @@ input.checkbox
 
 input.radio
 {
-	icon-decorator: image;
-	icon-image: invader.tga 407px 0px 437px 30px;
+	decorator: image(radio);
 }
 
 input.radio:hover
 {
-	icon-image-s: 437px 467px;
+	decorator: image(radio-hover);
 }
 
 input.radio:active
 {
-	icon-image-s: 467px 497px;
+	decorator: image(radio-active);
 }
 
 input.radio:checked
 {
-	icon-image-t: 30px 60px;
+	decorator: image(radio-checked);
 }
 
 input.radio:checked:hover
 {
-	icon-image-s: 437px 467px;
-	icon-image-t: 30px 60px;
+	decorator: image(radio-checked-hover);
 }
 
 input.radio:checked:active
 {
-	icon-image-s: 467px 497px;
-	icon-image-t: 30px 60px;
+	decorator: image(radio-checked-active);
 }
 
 input.checkbox
 {
-	icon-decorator: image;
-	icon-image: invader.tga 407px 60px 437px 90px;
+	decorator: image(checkbox);
 }
 
 input.checkbox:hover
 {
-	icon-image-s: 437px 467px;
+	decorator: image(checkbox-hover);
 }
 
 input.checkbox:active
 {
-	icon-image-s: 467px 497px;
+	decorator: image(checkbox-active);
 }
 
 input.checkbox:checked
 {
-	icon-image-t: 90px 120px;
+	decorator: image(checkbox-checked);
 }
 
 input.checkbox:checked:hover
 {
-	icon-image-s: 437px 467px;
-	icon-image-t: 90px 120px;
+	decorator: image(checkbox-checked-hover);
 }
 
 input.checkbox:checked:active
 {
-	icon-image-s: 467px 497px;
-	icon-image-t: 90px 120px;
+	decorator: image(checkbox-checked-active);
 }
 
-
-
 datagrid datagridheader
 {
 	width: auto;
 	height: 25px;
 	padding: 5px 10px 0px 10px;
 
-	background-decorator: tiled-horizontal;
-	background-left-image: invader.tga 127px 192px 143px 223px;
-	background-center-image: invader.tga stretch 143px 192px 145px 223px;
-	background-right-image: invader.tga 145px 192px 160px 223px;
+	decorator: tiled-horizontal( datagridheader-l, datagridheader-c, datagridheader-r );
 }
 
 datagrid datagridbody
@@ -423,25 +497,33 @@ datagridexpand
 	height: 17px;
 	width: 17px;
 	
-	icon-decorator: image;
-	icon-image: invader.tga 3px 232px 20px 249px;
+	decorator: image( datagridexpand );
 }
 
 datagridexpand:hover
 {
-	icon-image-s: 21px 38px;
+	decorator: image( datagridexpand-hover );
 }
 
 datagridexpand:active
 {
-	icon-image-s: 39px 56px;
+	decorator: image( datagridexpand-active  );
 }
 
 datagridexpand.collapsed
 {
-	icon-image-t: 250px 267px;
+	decorator: image( datagridexpand-collapsed );
 }
 
+datagridexpand.collapsed:hover
+{
+	decorator: image( datagridexpand-collapsed-hover );
+}
+
+datagridexpand.collapsed:active
+{
+	decorator: image( datagridexpand-collapsed-active  );
+}
 
 
 scrollbarvertical
@@ -454,10 +536,11 @@ scrollbarvertical
 
 scrollbarvertical slidertrack
 {
-	background-decorator: tiled-vertical;
-	background-top-image: invader.tga 70px 199px 97px 201px;
-	background-center-image: invader.tga stretch 70px 201px 97px 202px;
-	background-bottom-image: invader.tga 70px 203px 97px 204px;
+	decorator: tiled-vertical( slidertrack-t, slidertrack-c, slidertrack-b );
+}
+scrollbarvertical slidertrack:active
+{
+	image-color: #aaa;
 }
 
 scrollbarvertical sliderbar
@@ -466,57 +549,51 @@ scrollbarvertical sliderbar
 	width: 23px;
 	min-height: 46px;
 
-	background-decorator: tiled-vertical;
-	background-top-image: invader.tga 56px 152px 79px 175px;
-	background-center-image: invader.tga stretch 56px 175px 79px 175px;
-	background-bottom-image: invader.tga 56px 176px 79px 198px;
+	decorator: tiled-vertical( sliderbar-t, sliderbar-c, sliderbar-b );
 }
 
 scrollbarvertical sliderbar:hover
 {
-	background-top-image-s: 80px 103px;
-	background-center-image-s: 80px 103px;
-	background-bottom-image-s: 80px 103px;
+	decorator: tiled-vertical( sliderbar-hover-t, sliderbar-hover-c, sliderbar-hover-b );
 }
 
 scrollbarvertical sliderbar:active
 {
-	background-top-image-s: 104px 127px;
-	background-center-image-s: 104px 127px;
-	background-bottom-image-s: 104px 127px;
+	decorator: tiled-vertical( sliderbar-active-t, sliderbar-active-c, sliderbar-active-b );
 }
 
-scrollbarvertical sliderarrowdec
+scrollbarvertical sliderarrowdec,
+scrollbarvertical sliderarrowinc
 {
 	width: 27px;
 	height: 24px;
-	
-	icon-decorator: image;
-	icon-image: invader.tga 0px 152px 27px 176px;
 }
 
-scrollbarvertical sliderarrowdec:hover,
-scrollbarvertical sliderarrowinc:hover
+scrollbarvertical sliderarrowdec
 {
-	icon-image-t: 177px 201px;
+	decorator: image( sliderarrowdec );
 }
-
-scrollbarvertical sliderarrowdec:active,
-scrollbarvertical sliderarrowinc:active
+scrollbarvertical sliderarrowdec:hover
 {
-	icon-image-t: 202px 226px;
+	decorator: image( sliderarrowdec-hover );
+}
+scrollbarvertical sliderarrowdec:active
+{
+	decorator: image( sliderarrowdec-active );
 }
 
 scrollbarvertical sliderarrowinc
 {
-	width: 27px;
-	height: 24px;
-	
-	icon-decorator: image;
-	icon-image: invader.tga 28px 152px 55px 176px;
+	decorator: image( sliderarrowinc );
+}
+scrollbarvertical sliderarrowinc:hover
+{
+	decorator: image( sliderarrowinc-hover );
+}
+scrollbarvertical sliderarrowinc:active
+{
+	decorator: image( sliderarrowinc-active );
 }
-
-
 
 scrollbarhorizontal
 {

+ 4 - 4
Samples/basic/animation/src/main.cpp

@@ -50,8 +50,8 @@ public:
 		{
 			{
 				document->GetElementById("title")->SetInnerRML(title);
-				document->SetProperty("left", Property(position.x, Property::PX));
-				document->SetProperty("top", Property(position.y, Property::PX));
+				document->SetProperty(PropertyId::Left, Property(position.x, Property::PX));
+				document->SetProperty(PropertyId::Top, Property(position.y, Property::PX));
 				//document->Animate("opacity", Property(0.0f, Property::NUMBER), 2.0f, Tween{ Tween::Quadratic, Tween::InOut }, -1, true, 1.0f);
 			}
 
@@ -84,7 +84,7 @@ public:
 				auto el = document->GetElementById("exit");
 				PropertyDictionary pd;
 				StyleSheetSpecification::ParsePropertyDeclaration(pd, "transform", "translate(200px, 200px) rotate(1215deg)");
-				el->Animate("transform", *pd.GetProperty("transform"), 3.f, Tween{ Tween::Bounce, Tween::Out }, -1);
+				el->Animate("transform", *pd.GetProperty(PropertyId::Transform), 3.f, Tween{ Tween::Bounce, Tween::Out }, -1);
 			}
 
 			// Transform tests
@@ -176,7 +176,7 @@ void GameLoop()
 		ff += float(nudge)*0.3f;
 		auto el = window->GetDocument()->GetElementById("exit");
 		auto f = el->GetProperty<float>("margin-left");
-		el->SetProperty("margin-left", Rocket::Core::Property(ff, Rocket::Core::Property::PX));
+		el->SetProperty(Rocket::Core::PropertyId::MarginLeft, Rocket::Core::Property(ff, Rocket::Core::Property::PX));
 		float f_left = el->GetAbsoluteLeft();
 		Rocket::Core::Log::Message(Rocket::Core::Log::LT_INFO, "margin-left: '%f'   abs: %f.", ff, f_left);
 		nudge = 0;

+ 3 - 2
Samples/basic/benchmark/src/main.cpp

@@ -57,8 +57,8 @@ public:
 		{
 			{
 				document->GetElementById("title")->SetInnerRML(title);
-				document->SetProperty("left", Property(position.x, Property::PX));
-				document->SetProperty("top", Property(position.y, Property::PX));
+				document->SetProperty(PropertyId::Left, Property(position.x, Property::PX));
+				document->SetProperty(PropertyId::Top, Property(position.y, Property::PX));
 			}
 
 			document->Show();
@@ -104,6 +104,7 @@ public:
 		  Update definition speedup: 115.0  [5d138fa]
 		  (Full release mode, no code change): 135.0  [5d138fa]
 		  EventIDs: 139.0  [d2c3956]
+		  More on events and EventIDs: 146.0  [fd44d9c]
 		  
 		*/
 

+ 1 - 2
Samples/basic/drag/data/icon.rcss

@@ -10,8 +10,7 @@ icon
     padding: 60px 10px 0px 10px;
     margin: 10px;
     
-    background-decorator: image;
-    background-image: ../../../assets/present.tga 0px 0px 100px 100px;
+    decorator: image( ../../../assets/present.tga 0px 0px 100px 100px );
     
     font-size: 12px;
     text-align: center;

+ 3 - 2
Samples/basic/drag/src/Inventory.cpp

@@ -35,9 +35,10 @@ Inventory::Inventory(const Rocket::Core::String& title, const Rocket::Core::Vect
 	document = context->LoadDocument("data/inventory.rml");
 	if (document != NULL)
 	{
+		using Rocket::Core::PropertyId;
 		document->GetElementById("title")->SetInnerRML(title);
-		document->SetProperty("left", Rocket::Core::Property(position.x, Rocket::Core::Property::PX));
-		document->SetProperty("top", Rocket::Core::Property(position.y, Rocket::Core::Property::PX));
+		document->SetProperty(PropertyId::Left, Rocket::Core::Property(position.x, Rocket::Core::Property::PX));
+		document->SetProperty(PropertyId::Top, Rocket::Core::Property(position.y, Rocket::Core::Property::PX));
 		document->Show();
 	}
 

+ 2 - 2
Samples/basic/transform/src/main.cpp

@@ -43,8 +43,8 @@ public:
 		if (document != NULL)
 		{
 			document->GetElementById("title")->SetInnerRML(title);
-			document->SetProperty("left", Rocket::Core::Property(position.x, Rocket::Core::Property::PX));
-			document->SetProperty("top", Rocket::Core::Property(position.y, Rocket::Core::Property::PX));
+			document->SetProperty(Rocket::Core::PropertyId::Left, Rocket::Core::Property(position.x, Rocket::Core::Property::PX));
+			document->SetProperty(Rocket::Core::PropertyId::Top, Rocket::Core::Property(position.y, Rocket::Core::Property::PX));
 			document->Show();
 		}
 	}

+ 23 - 24
Samples/basic/treeview/data/treeview.rml

@@ -7,33 +7,32 @@
 		{
 			width: 450px;
 			height: 400px;
-            
-            margin: auto;
+			margin: auto;
 		}
 		
 		/* Hide the window icon. */
-        div#title_bar div#icon
-        {
-            display: none;
-        }
-        
-        datagridcell
-        {
-            text-align: left;
-        }
-        
-        datagridexpand
-        {
-            display: inline-block;
-            vertical-align: -3px;
-            margin-right: 2px;
-        }
-        
-        spacer
-        {
-            display: inline-block;
-            width: 25px;
-        }
+		div#title_bar div#icon
+		{
+			display: none;
+		}
+		
+		datagridcell
+		{
+			text-align: left;
+		}
+		
+		datagridexpand
+		{
+			display: inline-block;
+			vertical-align: -3px;
+			margin-right: 2px;
+		}
+		
+		spacer
+		{
+			display: inline-block;
+			width: 25px;
+		}
 	</style>
 </head>
 <body template="window">

+ 11 - 8
Samples/invaders/data/background.rml

@@ -7,6 +7,16 @@
 				height: 100%;
 				z-index: -1;
 			}
+			
+			@decorator star : starfield {
+				num-layers: 5;
+				top-colour: #fffc;
+				bottom-colour: #fff3;
+				top-speed: 80.0;
+				bottom-speed: 20.0;
+				top-density: 8;
+				bottom-density: 20;
+			}
 
 			starfield
 			{
@@ -15,14 +25,7 @@
 				height: 100%;
 				z-index: 1;
 
-				star-decorator: starfield;
-				star-num-layers: 5;
-				star-top-colour: #fffc;
-				star-bottom-colour: #fff3;
-				star-top-speed: 80.0;
-				star-bottom-speed: 20.0;
-				star-top-density: 8;
-				star-bottom-density: 20;
+				decorator: star;
 			}
 		</style>
 	</head>

+ 7 - 14
Samples/invaders/data/game.rml

@@ -20,7 +20,7 @@
 				width: 100%;
 				height: 100%;
 			}
-
+			
 			div
 			{
 				height: 47px;
@@ -29,10 +29,7 @@
 
 				font-size: 20px;
 
-				background-decorator: tiled-horizontal;
-				background-left-image: ../../assets/invader.tga 147px 55px 229px 0px;
-				background-center-image: ../../assets/invader.tga stretch 229px 55px 230px 0px;
-				background-right-image: ../../assets/invader.tga 231px 55px 246px 0px;
+				decorator: tiled-horizontal( huditem-l, huditem-c, huditem-r );
 			}
 
 			div#score_div
@@ -58,7 +55,7 @@
 				float: right;
 				width: 80px;
 			}
-
+			
 			icon
 			{
 				display: block;
@@ -68,30 +65,26 @@
 
 				width: 51px;
 				height: 39px;
-				
-				icon-decorator: image;
-				icon-image-src: ../../assets/invader.tga;
-				icon-image-t: 152px 191px;
 			}
 
 			div#score_div icon
 			{
-				icon-image-s: 434px 485px;
+				decorator: image( icon-score );
 			}
 
 			div#hiscore_div icon
 			{
-				icon-image-s: 281px 332px;
+				decorator: image( icon-hiscore );
 			}
 
 			div#waves_div icon
 			{
-				icon-image-s: 332px 383px;
+				decorator: image( icon-waves );
 			}
 
 			div#lives_div icon
 			{
-				icon-image-s: 383px 434px;
+				decorator: image( icon-lives );
 			}
 		</style>
 	</head>

+ 1 - 2
Samples/invaders/data/help.rml

@@ -17,8 +17,7 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 128px 179px;
-				icon-image-t: 152px 191px;
+				decorator: image( icon-help );
 			}
 		</style>
 	</head>

+ 2 - 4
Samples/invaders/data/high_score.rml

@@ -13,8 +13,7 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 281px 331px;
-				icon-image-t: 152px 191px;
+				decorator: image( icon-hiscore );
 			}
 			
 			datagrid
@@ -37,8 +36,7 @@
 				width: 64px;
 				height: 16px;
 				
-				defender-decorator: defender;
-				defender-image-src: high_scores_defender.tga;
+				decorator: defender( high_scores_defender.tga );
 			}			
 		</style>
 	</head>

+ 1 - 2
Samples/invaders/data/main_menu.rml

@@ -13,8 +13,7 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 179px 230px;
-				icon-image-t: 152px 191px;
+				decorator: image( icon-invader );
 			}
 		</style>
 	</head>

+ 1 - 3
Samples/invaders/data/options.rml

@@ -13,9 +13,7 @@
 
 			div#title_bar div#icon
 			{
-				icon-image-s: 230px 281px;
-				icon-image-t: 152px 191px;
-
+				decorator: image( icon-game );
 				display: none;
 			}
 

+ 1 - 2
Samples/invaders/data/pause.rml

@@ -13,8 +13,7 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 332px 383px;
-				icon-image-t: 191px 231px;
+				decorator: image( icon-flag );
 			}
 		</style>
 	</head>

+ 1 - 2
Samples/invaders/data/start_game.rml

@@ -13,8 +13,7 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 230px 281px;
-				icon-image-t: 152px 191px;
+				decorator: image( icon-game );
 			}
 			
 			form div

+ 7 - 20
Samples/invaders/src/DecoratorInstancerDefender.cpp

@@ -32,7 +32,8 @@
 
 DecoratorInstancerDefender::DecoratorInstancerDefender()
 {
-	RegisterProperty("image-src", "").AddParser("string");
+	id_image_src = RegisterProperty("image-src", "").AddParser("string").GetId();
+	RegisterShorthand("decorator", "image-src", Rocket::Core::ShorthandType::FallThrough);
 }
 
 DecoratorInstancerDefender::~DecoratorInstancerDefender()
@@ -40,30 +41,16 @@ DecoratorInstancerDefender::~DecoratorInstancerDefender()
 }
 
 // Instances a decorator given the property tag and attributes from the RCSS file.
-Rocket::Core::Decorator* DecoratorInstancerDefender::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties)
+std::shared_ptr<Rocket::Core::Decorator> DecoratorInstancerDefender::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface)
 {
 	ROCKET_UNUSED(name);
 
-	const Rocket::Core::Property* image_source_property = properties.GetProperty("image-src");
+	const Rocket::Core::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rocket::Core::String image_source = image_source_property->Get< Rocket::Core::String >();
 
-	DecoratorDefender* decorator = new DecoratorDefender();
+	auto decorator = std::make_shared<DecoratorDefender>();
 	if (decorator->Initialise(image_source, image_source_property->source))
 		return decorator;
-
-	decorator->RemoveReference();
-	ReleaseDecorator(decorator);
-	return NULL;
-}
-
-// Releases the given decorator.
-void DecoratorInstancerDefender::ReleaseDecorator(Rocket::Core::Decorator* decorator)
-{
-	delete decorator;
-}
-
-// Releases the instancer.
-void DecoratorInstancerDefender::Release()
-{
-	delete this;
+	
+	return nullptr;
 }

+ 4 - 7
Samples/invaders/src/DecoratorInstancerDefender.h

@@ -38,19 +38,16 @@ class DecoratorInstancerDefender : public Rocket::Core::DecoratorInstancer
 {
 public:
 	DecoratorInstancerDefender();
-	virtual ~DecoratorInstancerDefender();
+	~DecoratorInstancerDefender();
 
 	/// Instances a decorator given the property tag and attributes from the RCSS file.
 	/// @param[in] name The type of decorator desired. For example, "background-decorator: simple;" is declared as type "simple".
 	/// @param[in] properties All RCSS properties associated with the decorator.
 	/// @return The decorator if it was instanced successful, NULL if an error occured.
-	Rocket::Core::Decorator* InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties);
-	/// Releases the given decorator.
-	/// @param[in] decorator Decorator to release. This is guaranteed to have been constructed by this instancer.
-	void ReleaseDecorator(Rocket::Core::Decorator* decorator);
+	std::shared_ptr<Rocket::Core::Decorator> InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface) override;
 
-	/// Releases the instancer.
-	void Release();
+private:
+	Rocket::Core::PropertyId id_image_src;
 };
 
 #endif

+ 17 - 31
Samples/invaders/src/DecoratorInstancerStarfield.cpp

@@ -31,13 +31,13 @@
 
 DecoratorInstancerStarfield::DecoratorInstancerStarfield()
 {
-	RegisterProperty("num-layers", "3").AddParser("number");
-	RegisterProperty("top-colour", "#dddc").AddParser("color");
-	RegisterProperty("bottom-colour", "#333c").AddParser("color");
-	RegisterProperty("top-speed", "10.0").AddParser("number");
-	RegisterProperty("bottom-speed", "2.0").AddParser("number");
-	RegisterProperty("top-density", "15").AddParser("number");
-	RegisterProperty("bottom-density", "10").AddParser("number");
+	id_num_layers = RegisterProperty("num-layers", "3").AddParser("number").GetId();
+	id_top_colour = RegisterProperty("top-colour", "#dddc").AddParser("color").GetId();
+	id_bottom_colour = RegisterProperty("bottom-colour", "#333c").AddParser("color").GetId();
+	id_top_speed = RegisterProperty("top-speed", "10.0").AddParser("number").GetId();
+	id_bottom_speed = RegisterProperty("bottom-speed", "2.0").AddParser("number").GetId();
+	id_top_density = RegisterProperty("top-density", "15").AddParser("number").GetId();
+	id_bottom_density = RegisterProperty("bottom-density", "10").AddParser("number").GetId();
 }
 
 DecoratorInstancerStarfield::~DecoratorInstancerStarfield()
@@ -45,35 +45,21 @@ DecoratorInstancerStarfield::~DecoratorInstancerStarfield()
 }
 
 // Instances a decorator given the property tag and attributes from the RCSS file.
-Rocket::Core::Decorator* DecoratorInstancerStarfield::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties)
+std::shared_ptr<Rocket::Core::Decorator> DecoratorInstancerStarfield::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface)
 {
 	ROCKET_UNUSED(name);
 
-	int num_layers = Rocket::Core::Math::RealToInteger(properties.GetProperty("num-layers")->Get< float >());
-	Rocket::Core::Colourb top_colour = properties.GetProperty("top-colour")->Get< Rocket::Core::Colourb >();
-	Rocket::Core::Colourb bottom_colour = properties.GetProperty("bottom-colour")->Get< Rocket::Core::Colourb >();
-	float top_speed = properties.GetProperty("top-speed")->Get< float >();
-	float bottom_speed = properties.GetProperty("bottom-speed")->Get< float >();
-	int top_density = Rocket::Core::Math::RealToInteger(properties.GetProperty("top-density")->Get< float >());
-	int bottom_density = Rocket::Core::Math::RealToInteger(properties.GetProperty("bottom-density")->Get< float >());
+	int num_layers = Rocket::Core::Math::RealToInteger(properties.GetProperty(id_num_layers)->Get< float >());
+	Rocket::Core::Colourb top_colour = properties.GetProperty(id_top_colour)->Get< Rocket::Core::Colourb >();
+	Rocket::Core::Colourb bottom_colour = properties.GetProperty(id_bottom_colour)->Get< Rocket::Core::Colourb >();
+	float top_speed = properties.GetProperty(id_top_speed)->Get< float >();
+	float bottom_speed = properties.GetProperty(id_bottom_speed)->Get< float >();
+	int top_density = Rocket::Core::Math::RealToInteger(properties.GetProperty(id_top_density)->Get< float >());
+	int bottom_density = Rocket::Core::Math::RealToInteger(properties.GetProperty(id_bottom_density)->Get< float >());
 
-	DecoratorStarfield* decorator = new DecoratorStarfield();
+	auto decorator = std::make_shared<DecoratorStarfield>();
 	if (decorator->Initialise(num_layers, top_colour, bottom_colour, top_speed, bottom_speed, top_density, bottom_density))
 		return decorator;
 
-	decorator->RemoveReference();
-	ReleaseDecorator(decorator);
-	return NULL;
-}
-
-// Releases the given decorator.
-void DecoratorInstancerStarfield::ReleaseDecorator(Rocket::Core::Decorator* decorator)
-{
-	delete decorator;
-}
-
-// Releases the instancer.
-void DecoratorInstancerStarfield::Release()
-{
-	delete this;
+	return nullptr;
 }

+ 4 - 7
Samples/invaders/src/DecoratorInstancerStarfield.h

@@ -39,19 +39,16 @@ class DecoratorInstancerStarfield : public Rocket::Core::DecoratorInstancer
 {
 public:
 	DecoratorInstancerStarfield();
-	virtual ~DecoratorInstancerStarfield();
+	~DecoratorInstancerStarfield();
 
 	/// Instances a decorator given the property tag and attributes from the RCSS file.
 	/// @param name The type of decorator desired. For example, "background-decorator: simple;" is declared as type "simple".
 	/// @param properties All RCSS properties associated with the decorator.
 	/// @return The decorator if it was instanced successful, NULL if an error occured.
-	Rocket::Core::Decorator* InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties);
-	/// Releases the given decorator.
-	/// @param decorator Decorator to release. This is guaranteed to have been constructed by this instancer.
-	void ReleaseDecorator(Rocket::Core::Decorator* decorator);
+	std::shared_ptr<Rocket::Core::Decorator> InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface) override;
 
-	/// Releases the instancer.
-	void Release();
+private:
+	Rocket::Core::PropertyId id_num_layers, id_top_colour, id_bottom_colour, id_top_speed, id_bottom_speed, id_top_density, id_bottom_density;
 };
 
 #endif

+ 2 - 2
Samples/invaders/src/EventHandlerOptions.cpp

@@ -141,9 +141,9 @@ void EventHandlerOptions::ProcessEvent(Rocket::Core::Event& event, const Rocket:
 			// The 'value' parameter of an onchange event is set to the value the control would send if it was
 			// submitted; so, the empty string if it is clear or to the 'value' attribute of the control if it is set.
 			if (event.GetParameter< String >("value", "").empty())
-				bad_warning->SetProperty("display", Property(Style::Display::None));
+				bad_warning->SetProperty(PropertyId::Display, Property(Style::Display::None));
 			else
-				bad_warning->SetProperty("display", Property(Style::Display::Block));
+				bad_warning->SetProperty(PropertyId::Display, Property(Style::Display::Block));
 		}
 	}
 	else if (value == "enable_accept")

+ 2 - 7
Samples/invaders/src/main.cpp

@@ -129,13 +129,8 @@ int main(int ROCKET_UNUSED_PARAMETER(argc), char** ROCKET_UNUSED_PARAMETER(argv)
 	Rocket::Core::Factory::RegisterElementInstancer("game", element_instancer);
 	element_instancer->RemoveReference();
 
-	Rocket::Core::DecoratorInstancer* decorator_instancer = new DecoratorInstancerStarfield();
-	Rocket::Core::Factory::RegisterDecoratorInstancer("starfield", decorator_instancer);
-	decorator_instancer->RemoveReference();
-
-	decorator_instancer = new DecoratorInstancerDefender();
-	Rocket::Core::Factory::RegisterDecoratorInstancer("defender", decorator_instancer);
-	decorator_instancer->RemoveReference();
+	Rocket::Core::Factory::RegisterDecoratorInstancer("starfield", std::make_unique<DecoratorInstancerStarfield>());
+	Rocket::Core::Factory::RegisterDecoratorInstancer("defender", std::make_unique<DecoratorInstancerDefender>());
 
 	// Register Invader's data formatters
 	HighScoresNameFormatter name_formatter;

+ 11 - 10
Samples/luainvaders/data/background.rml

@@ -5,10 +5,18 @@
 			{
 				width: 100%;
 				height: 100%;
-				z-index: bottom;
-
 				z-index: -1;
 			}
+			
+			@decorator star : starfield {
+				num-layers: 5;
+				top-colour: #fffc;
+				bottom-colour: #fff3;
+				top-speed: 80.0;
+				bottom-speed: 20.0;
+				top-density: 8;
+				bottom-density: 20;
+			}
 
 			starfield
 			{
@@ -17,14 +25,7 @@
 				height: 100%;
 				z-index: 1;
 
-				star-decorator: starfield;
-				star-num-layers: 5;
-				star-top-colour: #fffc;
-				star-bottom-colour: #fff3;
-				star-top-speed: 80.0;
-				star-bottom-speed: 20.0;
-				star-top-density: 8;
-				star-bottom-density: 20;
+				decorator: star;
 			}
 		</style>
 	</head>

+ 5 - 12
Samples/luainvaders/data/game.rml

@@ -28,10 +28,7 @@
 
 				font-size: 20px;
 
-				background-decorator: tiled-horizontal;
-				background-left-image: ../../assets/invader.tga 147px 55px 229px 0px;
-				background-center-image: ../../assets/invader.tga stretch 229px 55px 230px 0px;
-				background-right-image: ../../assets/invader.tga 231px 55px 246px 0px;
+				decorator: tiled-horizontal( huditem-l, huditem-c, huditem-r );
 			}
 
 			div#score_div
@@ -67,30 +64,26 @@
 
 				width: 51px;
 				height: 39px;
-				
-				icon-decorator: image;
-				icon-image-src: ../../assets/invader.tga;
-				icon-image-t: 152px 191px;
 			}
 
 			div#score_div icon
 			{
-				icon-image-s: 434px 485px;
+				decorator: image( icon-score );
 			}
 
 			div#hiscore_div icon
 			{
-				icon-image-s: 281px 332px;
+				decorator: image( icon-hiscore );
 			}
 
 			div#waves_div icon
 			{
-				icon-image-s: 332px 383px;
+				decorator: image( icon-waves );
 			}
 
 			div#lives_div icon
 			{
-				icon-image-s: 383px 434px;
+				decorator: image( icon-lives );
 			}
 		</style>
 		<script>

+ 1 - 2
Samples/luainvaders/data/help.rml

@@ -17,8 +17,7 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 128px 179px;
-				icon-image-t: 152px 191px;
+				decorator: image( icon-help );
 			}
 		</style>
 	</head>

+ 3 - 6
Samples/luainvaders/data/high_score.rml

@@ -13,14 +13,12 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 281px 331px;
-				icon-image-t: 152px 191px;
+				decorator: image( icon-hiscore );
 			}
 			
 			datagrid
 			{
 				margin-bottom: 20px;
-				min-rows: 10;
 			}
 			
 			datagrid data_grid_body
@@ -34,8 +32,7 @@
 				width: 64px;
 				height: 16px;
 				
-				defender-decorator: defender;
-				defender-image-src: high_scores_defender.tga;
+				decorator: defender( high_scores_defender.tga );
 			}
 		</style>
 		<script>
@@ -65,7 +62,7 @@ end
 		</script>
 	</head>
 	<body template="luawindow" onload="HighScore.OnLoad(document) Game.SubmitHighScore()" onunload="Game.SetHighScoreName('Anon')">
-		<datagrid id="datagrid" source="high_scores.scores">
+		<datagrid id="datagrid" source="high_scores.scores" min-rows"10">
 			<col fields="name,name_required" formatter="name" width="40%">Pilot:</col>
 			<col fields="colour" formatter="ship" width="20%">Ship:</col>
 			<col fields="wave" width="20%">Wave:</col>

+ 1 - 2
Samples/luainvaders/data/main_menu.rml

@@ -13,8 +13,7 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 179px 230px;
-				icon-image-t: 152px 191px;
+				decorator: image( icon-invader );
 			}
 		</style>
 		<script>

+ 1 - 3
Samples/luainvaders/data/options.rml

@@ -13,9 +13,7 @@
 
 			div#title_bar div#icon
 			{
-				icon-image-s: 230px 281px;
-				icon-image-t: 152px 191px;
-
+				decorator: image( icon-game );
 				display: none;
 			}
 

+ 1 - 2
Samples/luainvaders/data/pause.rml

@@ -13,8 +13,7 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 332px 383px;
-				icon-image-t: 191px 231px;
+				decorator: image( icon-flag );
 			}
 		</style>
 	</head>

+ 1 - 2
Samples/luainvaders/data/start_game.rml

@@ -13,8 +13,7 @@
 			
 			div#title_bar div#icon
 			{
-				icon-image-s: 230px 281px;
-				icon-image-t: 152px 191px;
+				decorator: image( icon-game );
 			}
 			
 			form div

+ 6 - 19
Samples/luainvaders/src/DecoratorInstancerDefender.cpp

@@ -32,7 +32,8 @@
 
 DecoratorInstancerDefender::DecoratorInstancerDefender()
 {
-	RegisterProperty("image-src", "").AddParser("string");
+	id_image_src = RegisterProperty("image-src", "").AddParser("string").GetId();
+	RegisterShorthand("decorator", "image-src", Rocket::Core::ShorthandType::FallThrough);
 }
 
 DecoratorInstancerDefender::~DecoratorInstancerDefender()
@@ -40,30 +41,16 @@ DecoratorInstancerDefender::~DecoratorInstancerDefender()
 }
 
 // Instances a decorator given the property tag and attributes from the RCSS file.
-Rocket::Core::Decorator* DecoratorInstancerDefender::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties)
+std::shared_ptr<Rocket::Core::Decorator> DecoratorInstancerDefender::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface)
 {
 	ROCKET_UNUSED(name);
 
-	const Rocket::Core::Property* image_source_property = properties.GetProperty("image-src");
+	const Rocket::Core::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rocket::Core::String image_source = image_source_property->Get< Rocket::Core::String >();
 
-	DecoratorDefender* decorator = new DecoratorDefender();
+	auto decorator = std::make_shared<DecoratorDefender>();
 	if (decorator->Initialise(image_source, image_source_property->source))
 		return decorator;
 
-	decorator->RemoveReference();
-	ReleaseDecorator(decorator);
-	return NULL;
-}
-
-// Releases the given decorator.
-void DecoratorInstancerDefender::ReleaseDecorator(Rocket::Core::Decorator* decorator)
-{
-	delete decorator;
-}
-
-// Releases the instancer.
-void DecoratorInstancerDefender::Release()
-{
-	delete this;
+	return nullptr;
 }

+ 4 - 7
Samples/luainvaders/src/DecoratorInstancerDefender.h

@@ -38,19 +38,16 @@ class DecoratorInstancerDefender : public Rocket::Core::DecoratorInstancer
 {
 public:
 	DecoratorInstancerDefender();
-	virtual ~DecoratorInstancerDefender();
+	~DecoratorInstancerDefender();
 
 	/// Instances a decorator given the property tag and attributes from the RCSS file.
 	/// @param[in] name The type of decorator desired. For example, "background-decorator: simple;" is declared as type "simple".
 	/// @param[in] properties All RCSS properties associated with the decorator.
 	/// @return The decorator if it was instanced successful, NULL if an error occured.
-	Rocket::Core::Decorator* InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties);
-	/// Releases the given decorator.
-	/// @param[in] decorator Decorator to release. This is guaranteed to have been constructed by this instancer.
-	void ReleaseDecorator(Rocket::Core::Decorator* decorator);
+	std::shared_ptr<Rocket::Core::Decorator> InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface) override;
 
-	/// Releases the instancer.
-	void Release();
+private:
+	Rocket::Core::PropertyId id_image_src;
 };
 
 #endif

+ 17 - 32
Samples/luainvaders/src/DecoratorInstancerStarfield.cpp

@@ -27,18 +27,17 @@
 
 #include "DecoratorStarfield.h"
 #include <Rocket/Core/Math.h>
-#include <Rocket/Core/Types.h>
 #include "DecoratorInstancerStarfield.h"
 
 DecoratorInstancerStarfield::DecoratorInstancerStarfield()
 {
-	RegisterProperty("num-layers", "3").AddParser("number");
-	RegisterProperty("top-colour", "#dddc").AddParser("color");
-	RegisterProperty("bottom-colour", "#333c").AddParser("color");
-	RegisterProperty("top-speed", "10.0").AddParser("number");
-	RegisterProperty("bottom-speed", "2.0").AddParser("number");
-	RegisterProperty("top-density", "15").AddParser("number");
-	RegisterProperty("bottom-density", "10").AddParser("number");
+	id_num_layers = RegisterProperty("num-layers", "3").AddParser("number").GetId();
+	id_top_colour = RegisterProperty("top-colour", "#dddc").AddParser("color").GetId();
+	id_bottom_colour = RegisterProperty("bottom-colour", "#333c").AddParser("color").GetId();
+	id_top_speed = RegisterProperty("top-speed", "10.0").AddParser("number").GetId();
+	id_bottom_speed = RegisterProperty("bottom-speed", "2.0").AddParser("number").GetId();
+	id_top_density = RegisterProperty("top-density", "15").AddParser("number").GetId();
+	id_bottom_density = RegisterProperty("bottom-density", "10").AddParser("number").GetId();
 }
 
 DecoratorInstancerStarfield::~DecoratorInstancerStarfield()
@@ -46,35 +45,21 @@ DecoratorInstancerStarfield::~DecoratorInstancerStarfield()
 }
 
 // Instances a decorator given the property tag and attributes from the RCSS file.
-Rocket::Core::Decorator* DecoratorInstancerStarfield::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties)
+std::shared_ptr<Rocket::Core::Decorator> DecoratorInstancerStarfield::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface)
 {
 	ROCKET_UNUSED(name);
 
-	int num_layers = Rocket::Core::Math::RealToInteger(properties.GetProperty("num-layers")->Get< float >());
-	Rocket::Core::Colourb top_colour = properties.GetProperty("top-colour")->Get< Rocket::Core::Colourb >();
-	Rocket::Core::Colourb bottom_colour = properties.GetProperty("bottom-colour")->Get< Rocket::Core::Colourb >();
-	float top_speed = properties.GetProperty("top-speed")->Get< float >();
-	float bottom_speed = properties.GetProperty("bottom-speed")->Get< float >();
-	int top_density = Rocket::Core::Math::RealToInteger(properties.GetProperty("top-density")->Get< float >());
-	int bottom_density = Rocket::Core::Math::RealToInteger(properties.GetProperty("bottom-density")->Get< float >());
+	int num_layers = Rocket::Core::Math::RealToInteger(properties.GetProperty(id_num_layers)->Get< float >());
+	Rocket::Core::Colourb top_colour = properties.GetProperty(id_top_colour)->Get< Rocket::Core::Colourb >();
+	Rocket::Core::Colourb bottom_colour = properties.GetProperty(id_bottom_colour)->Get< Rocket::Core::Colourb >();
+	float top_speed = properties.GetProperty(id_top_speed)->Get< float >();
+	float bottom_speed = properties.GetProperty(id_bottom_speed)->Get< float >();
+	int top_density = Rocket::Core::Math::RealToInteger(properties.GetProperty(id_top_density)->Get< float >());
+	int bottom_density = Rocket::Core::Math::RealToInteger(properties.GetProperty(id_bottom_density)->Get< float >());
 
-	DecoratorStarfield* decorator = new DecoratorStarfield();
+	auto decorator = std::make_shared<DecoratorStarfield>();
 	if (decorator->Initialise(num_layers, top_colour, bottom_colour, top_speed, bottom_speed, top_density, bottom_density))
 		return decorator;
 
-	decorator->RemoveReference();
-	ReleaseDecorator(decorator);
-	return NULL;
-}
-
-// Releases the given decorator.
-void DecoratorInstancerStarfield::ReleaseDecorator(Rocket::Core::Decorator* decorator)
-{
-	delete decorator;
-}
-
-// Releases the instancer.
-void DecoratorInstancerStarfield::Release()
-{
-	delete this;
+	return nullptr;
 }

+ 4 - 7
Samples/luainvaders/src/DecoratorInstancerStarfield.h

@@ -39,19 +39,16 @@ class DecoratorInstancerStarfield : public Rocket::Core::DecoratorInstancer
 {
 public:
 	DecoratorInstancerStarfield();
-	virtual ~DecoratorInstancerStarfield();
+	~DecoratorInstancerStarfield();
 
 	/// Instances a decorator given the property tag and attributes from the RCSS file.
 	/// @param name The type of decorator desired. For example, "background-decorator: simple;" is declared as type "simple".
 	/// @param properties All RCSS properties associated with the decorator.
 	/// @return The decorator if it was instanced successful, NULL if an error occured.
-	Rocket::Core::Decorator* InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties);
-	/// Releases the given decorator.
-	/// @param decorator Decorator to release. This is guaranteed to have been constructed by this instancer.
-	void ReleaseDecorator(Rocket::Core::Decorator* decorator);
+	std::shared_ptr<Rocket::Core::Decorator> InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface) override;
 
-	/// Releases the instancer.
-	void Release();
+private:
+	Rocket::Core::PropertyId id_num_layers, id_top_colour, id_bottom_colour, id_top_speed, id_bottom_speed, id_top_density, id_bottom_density;
 };
 
 #endif

+ 2 - 7
Samples/luainvaders/src/main.cpp

@@ -118,13 +118,8 @@ int main(int, char**)
 	Shell::LoadFonts("../assets/");
 
 	// Register Invader's custom decorator instancers.
-	Rocket::Core::DecoratorInstancer* decorator_instancer = new DecoratorInstancerStarfield();
-	Rocket::Core::Factory::RegisterDecoratorInstancer("starfield", decorator_instancer);
-	decorator_instancer->RemoveReference();
-
-	decorator_instancer = new DecoratorInstancerDefender();
-	Rocket::Core::Factory::RegisterDecoratorInstancer("defender", decorator_instancer);
-	decorator_instancer->RemoveReference();	
+	Rocket::Core::Factory::RegisterDecoratorInstancer("starfield", std::make_unique<DecoratorInstancerStarfield>());
+	Rocket::Core::Factory::RegisterDecoratorInstancer("defender", std::make_unique<DecoratorInstancerDefender>());
 
 	// Construct the game singletons.
 	HighScores::Initialise();

+ 70 - 41
Samples/tutorial/datagrid/data/tutorial.rcss

@@ -1,3 +1,44 @@
+@spritesheet theme 
+{
+	src: ../../../assets/invader.tga;
+
+	title-bar-l: 147px 0px 82px 85px;
+	title-bar-c: 229px 0px  1px 85px;
+	title-bar-r: 231px 0px 15px 85px;
+	
+	window-tl: 0px 0px 133px 140px;
+	window-t:  134px 0px 1px 140px;
+	window-tr: 136px 0px 10px 140px;
+	window-l:  0px 139px 10px 1px;
+	window-c:  11px 139px 1px 1px;
+	window-r:  10px 139px -10px 1px; /* mirrored left */
+	window-bl: 0px 140px 11px 11px;
+	window-b:  11px 140px 1px 11px;
+	window-br: 136px 140px 10px 11px;
+	
+	slidertrack-t: 70px 199px 27px 2px;
+	slidertrack-c: 70px 201px 27px 1px;
+	slidertrack-b: 70px 202px 27px 2px;
+	
+	sliderbar-t:         56px 152px 23px 23px;
+	sliderbar-c:         56px 175px 23px 1px;
+	sliderbar-b:         56px 176px 23px 22px;
+	sliderbar-hover-t:   80px 152px 23px 23px;
+	sliderbar-hover-c:   80px 175px 23px 1px;
+	sliderbar-hover-b:   80px 176px 23px 22px;
+	sliderbar-active-t: 104px 152px 23px 23px;
+	sliderbar-active-c: 104px 175px 23px 1px;
+	sliderbar-active-b: 104px 176px 23px 22px;
+	 
+	sliderarrowdec: 0px 152px 27px 24px;
+	sliderarrowdec-hover: 0px 177px 27px 24px;
+	sliderarrowdec-active: 0px 202px 27px 24px;
+	
+	sliderarrowinc: 28px 152px 27px 24px;
+	sliderarrowinc-hover: 28px 177px 27px 24px;
+	sliderarrowinc-active: 28px 202px 27px 24px;
+}
+
 body
 {
 	font-family: Delicious;
@@ -9,19 +50,14 @@ body
 
 body.window
 {
-	background-decorator: tiled-box;
-	background-top-left-image: ../../../assets/invader.tga 0px 0px 133px 140px;
-	background-top-right-image: ../../../assets/invader.tga 136px 0px 146px 140px;
-	background-top-image: ../../../assets/invader.tga stretch 134px 0px 135px 140px;
-	background-bottom-left-image: ../../../assets/invader.tga 0px 140px 11px 151px;
-	background-bottom-right-image: ../../../assets/invader.tga 136px 140px 146px 151px;
-	background-bottom-image: ../../../assets/invader.tga stretch 11px 140px 12px 151px;
-	background-left-image: ../../../assets/invader.tga stretch 0px 139px 10px 140px;
-	background-center-image: ../../../assets/invader.tga stretch 11px 139px 12px 140px;
-	
 	padding: 10px 15px;
+	
+	decorator: tiled-box(
+		window-tl, window-t, window-tr, 
+		window-l, window-c, window-r,
+		window-bl, window-b, window-br
+	);
 }
-
 div#title-bar
 {
 	position: absolute;
@@ -39,11 +75,8 @@ div#title-bar span
 	font-weight: bold;
 
 	text-shadow: 2px 2px black;
-
-	background-decorator: tiled-horizontal;
-	background-left-image: ../../../assets/invader.tga 147px 0px 229px 85px;
-	background-center-image: ../../../assets/invader.tga stretch 229px 0px 230px 85px;
-	background-right-image: ../../../assets/invader.tga 231px 0px 246px 85px;
+	
+	decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
 }
 
 div#content
@@ -56,18 +89,19 @@ div#content
 
 scrollbarvertical
 {
-	width: 27px;
 	margin-top: -6px;
 	margin-bottom: -6px;
 	margin-right: -11px;
+	width: 27px;
 }
 
 scrollbarvertical slidertrack
 {
-	background-decorator: tiled-vertical;
-	background-top-image: ../../../assets/invader.tga 56px 199px 83px 201px;
-	background-center-image: ../../../assets/invader.tga stretch 56px 201px 83px 202px;
-	background-bottom-image: ../../../assets/invader.tga 56px 203px 83px 204px;
+	decorator: tiled-vertical( slidertrack-t, slidertrack-c, slidertrack-b );
+}
+scrollbarvertical slidertrack:active
+{
+	image-color: #aaa;
 }
 
 scrollbarvertical sliderbar
@@ -76,24 +110,17 @@ scrollbarvertical sliderbar
 	width: 23px;
 	min-height: 46px;
 
-	background-decorator: tiled-vertical;
-	background-top-image: ../../../assets/invader.tga 56px 152px 79px 175px;
-	background-center-image: ../../../assets/invader.tga stretch 56px 175px 79px 175px;
-	background-bottom-image: ../../../assets/invader.tga 56px 176px 79px 198px;
+	decorator: tiled-vertical( sliderbar-t, sliderbar-c, sliderbar-b );
 }
 
 scrollbarvertical sliderbar:hover
 {
-	background-top-image-s: 80px 103px;
-	background-center-image-s: 80px 103px;
-	background-bottom-image-s: 80px 103px;
+	decorator: tiled-vertical( sliderbar-hover-t, sliderbar-hover-c, sliderbar-hover-b );
 }
 
 scrollbarvertical sliderbar:active
 {
-	background-top-image-s: 104px 127px;
-	background-center-image-s: 104px 127px;
-	background-bottom-image-s: 104px 127px;
+	decorator: tiled-vertical( sliderbar-active-t, sliderbar-active-c, sliderbar-active-b );
 }
 
 scrollbarvertical sliderarrowdec,
@@ -105,24 +132,26 @@ scrollbarvertical sliderarrowinc
 
 scrollbarvertical sliderarrowdec
 {
-	icon-decorator: image;
-	icon-image: ../../../assets/invader.tga 0px 152px 27px 176px;
+	decorator: image( sliderarrowdec );
+}
+scrollbarvertical sliderarrowdec:hover
+{
+	decorator: image( sliderarrowdec-hover );
+}
+scrollbarvertical sliderarrowdec:active
+{
+	decorator: image( sliderarrowdec-active );
 }
 
 scrollbarvertical sliderarrowinc
 {
-	icon-decorator: image;
-	icon-image: ../../../assets/invader.tga 28px 152px 55px 176px;
+	decorator: image( sliderarrowinc );
 }
-
-scrollbarvertical sliderarrowdec:hover,
 scrollbarvertical sliderarrowinc:hover
 {
-	icon-image-t: 177px 201px;
+	decorator: image( sliderarrowinc-hover );
 }
-
-scrollbarvertical sliderarrowdec:active,
 scrollbarvertical sliderarrowinc:active
 {
-	icon-image-t: 202px 226px;
+	decorator: image( sliderarrowinc-active );
 }

+ 8 - 9
Samples/tutorial/datagrid/data/tutorial.rml

@@ -10,16 +10,15 @@
 
 			margin: auto;
 		}
-        
-        defender
-        {
-            display: block;
-            width: 64px;
-            height: 16px;
+    
+		defender
+		{
+				display: block;
+				width: 64px;
+				height: 16px;
 
-            defender-decorator: defender;
-            defender-image-src: ../../../assets/high_scores_defender.tga;
-        }
+				decorator: defender( ../../../assets/high_scores_defender.tga );
+		}
 	</style>
 </head>
 <body template="window">

+ 6 - 7
Samples/tutorial/datagrid/src/DecoratorInstancerDefender.cpp

@@ -16,7 +16,8 @@
 
 DecoratorInstancerDefender::DecoratorInstancerDefender()
 {
-	RegisterProperty("image-src", "").AddParser("string");
+	id_image_src = RegisterProperty("image-src", "").AddParser("string").GetId();
+	RegisterShorthand("decorator", "image-src", Rocket::Core::ShorthandType::FallThrough);
 }
 
 DecoratorInstancerDefender::~DecoratorInstancerDefender()
@@ -24,20 +25,18 @@ DecoratorInstancerDefender::~DecoratorInstancerDefender()
 }
 
 // Instances a decorator given the property tag and attributes from the RCSS file.
-Rocket::Core::Decorator* DecoratorInstancerDefender::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties)
+std::shared_ptr<Rocket::Core::Decorator> DecoratorInstancerDefender::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface)
 {
 	ROCKET_UNUSED(name);
 
-	const Rocket::Core::Property* image_source_property = properties.GetProperty("image-src");
+	const Rocket::Core::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rocket::Core::String image_source = image_source_property->Get< Rocket::Core::String >();
 
-	DecoratorDefender* decorator = new DecoratorDefender();
+	auto decorator = std::make_shared<DecoratorDefender>();
 	if (decorator->Initialise(image_source, image_source_property->source))
 		return decorator;
 
-	decorator->RemoveReference();
-	ReleaseDecorator(decorator);
-	return NULL;
+	return nullptr;
 }
 
 // Releases the given decorator.

+ 9 - 4
Samples/tutorial/datagrid/src/DecoratorInstancerDefender.h

@@ -26,16 +26,21 @@ public:
 	virtual ~DecoratorInstancerDefender();
 
 	/// Instances a decorator given the property tag and attributes from the RCSS file.
-	/// @param name The type of decorator desired. For example, "background-decorator: simple;" is declared as type "simple".
-	/// @param properties All RCSS properties associated with the decorator.
-	/// @return The decorator if it was instanced successful, NULL if an error occured.
-	Rocket::Core::Decorator* InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties);
+	/// @param[in] name The type of decorator desired. For example, "decorator: simple(...);" is declared as type "simple".
+	/// @param[in] properties All RCSS properties associated with the decorator.
+	/// @param[in] interface An interface for querying the active style sheet.
+	/// @return A shared_ptr to the decorator if it was instanced successfully.
+	std::shared_ptr<Rocket::Core::Decorator> InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface) override;
+
 	/// Releases the given decorator.
 	/// @param decorator Decorator to release. This is guaranteed to have been constructed by this instancer.
 	void ReleaseDecorator(Rocket::Core::Decorator* decorator);
 
 	/// Releases the instancer.
 	void Release();
+
+private:
+	Rocket::Core::PropertyId id_image_src;
 };
 
 #endif

+ 1 - 3
Samples/tutorial/datagrid/src/main.cpp

@@ -94,9 +94,7 @@ int main(int ROCKET_UNUSED_PARAMETER(argc), char** ROCKET_UNUSED_PARAMETER(argv)
 	Shell::LoadFonts("../../assets/");
 
 	// Load the defender decorator.
-	Rocket::Core::DecoratorInstancer* decorator_instancer = Rocket::Core::Factory::RegisterDecoratorInstancer("defender", new DecoratorInstancerDefender());
-	if (decorator_instancer != NULL)
-		decorator_instancer->RemoveReference();
+	Rocket::Core::Factory::RegisterDecoratorInstancer("defender", std::make_unique<DecoratorInstancerDefender>());
 
 	// Construct the high scores.
 	HighScores::Initialise();

+ 70 - 41
Samples/tutorial/datagrid_tree/data/tutorial.rcss

@@ -1,3 +1,44 @@
+@spritesheet theme 
+{
+	src: ../../../assets/invader.tga;
+
+	title-bar-l: 147px 0px 82px 85px;
+	title-bar-c: 229px 0px  1px 85px;
+	title-bar-r: 231px 0px 15px 85px;
+	
+	window-tl: 0px 0px 133px 140px;
+	window-t:  134px 0px 1px 140px;
+	window-tr: 136px 0px 10px 140px;
+	window-l:  0px 139px 10px 1px;
+	window-c:  11px 139px 1px 1px;
+	window-r:  10px 139px -10px 1px; /* mirrored left */
+	window-bl: 0px 140px 11px 11px;
+	window-b:  11px 140px 1px 11px;
+	window-br: 136px 140px 10px 11px;
+	
+	slidertrack-t: 70px 199px 27px 2px;
+	slidertrack-c: 70px 201px 27px 1px;
+	slidertrack-b: 70px 202px 27px 2px;
+	
+	sliderbar-t:         56px 152px 23px 23px;
+	sliderbar-c:         56px 175px 23px 1px;
+	sliderbar-b:         56px 176px 23px 22px;
+	sliderbar-hover-t:   80px 152px 23px 23px;
+	sliderbar-hover-c:   80px 175px 23px 1px;
+	sliderbar-hover-b:   80px 176px 23px 22px;
+	sliderbar-active-t: 104px 152px 23px 23px;
+	sliderbar-active-c: 104px 175px 23px 1px;
+	sliderbar-active-b: 104px 176px 23px 22px;
+	 
+	sliderarrowdec: 0px 152px 27px 24px;
+	sliderarrowdec-hover: 0px 177px 27px 24px;
+	sliderarrowdec-active: 0px 202px 27px 24px;
+	
+	sliderarrowinc: 28px 152px 27px 24px;
+	sliderarrowinc-hover: 28px 177px 27px 24px;
+	sliderarrowinc-active: 28px 202px 27px 24px;
+}
+
 body
 {
 	font-family: Delicious;
@@ -9,19 +50,14 @@ body
 
 body.window
 {
-	background-decorator: tiled-box;
-	background-top-left-image: ../../../assets/invader.tga 0px 0px 133px 140px;
-	background-top-right-image: ../../../assets/invader.tga 136px 0px 146px 140px;
-	background-top-image: ../../../assets/invader.tga stretch 134px 0px 135px 140px;
-	background-bottom-left-image: ../../../assets/invader.tga 0px 140px 11px 151px;
-	background-bottom-right-image: ../../../assets/invader.tga 136px 140px 146px 151px;
-	background-bottom-image: ../../../assets/invader.tga stretch 11px 140px 12px 151px;
-	background-left-image: ../../../assets/invader.tga stretch 0px 139px 10px 140px;
-	background-center-image: ../../../assets/invader.tga stretch 11px 139px 12px 140px;
-	
 	padding: 10px 15px;
+	
+	decorator: tiled-box(
+		window-tl, window-t, window-tr, 
+		window-l, window-c, window-r,
+		window-bl, window-b, window-br
+	);
 }
-
 div#title-bar
 {
 	position: absolute;
@@ -39,11 +75,8 @@ div#title-bar span
 	font-weight: bold;
 
 	text-shadow: 2px 2px black;
-
-	background-decorator: tiled-horizontal;
-	background-left-image: ../../../assets/invader.tga 147px 0px 229px 85px;
-	background-center-image: ../../../assets/invader.tga stretch 229px 0px 230px 85px;
-	background-right-image: ../../../assets/invader.tga 231px 0px 246px 85px;
+	
+	decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
 }
 
 div#content
@@ -56,18 +89,19 @@ div#content
 
 scrollbarvertical
 {
-	width: 27px;
 	margin-top: -6px;
 	margin-bottom: -6px;
 	margin-right: -11px;
+	width: 27px;
 }
 
 scrollbarvertical slidertrack
 {
-	background-decorator: tiled-vertical;
-	background-top-image: ../../../assets/invader.tga 56px 199px 83px 201px;
-	background-center-image: ../../../assets/invader.tga stretch 56px 201px 83px 202px;
-	background-bottom-image: ../../../assets/invader.tga 56px 203px 83px 204px;
+	decorator: tiled-vertical( slidertrack-t, slidertrack-c, slidertrack-b );
+}
+scrollbarvertical slidertrack:active
+{
+	image-color: #aaa;
 }
 
 scrollbarvertical sliderbar
@@ -76,24 +110,17 @@ scrollbarvertical sliderbar
 	width: 23px;
 	min-height: 46px;
 
-	background-decorator: tiled-vertical;
-	background-top-image: ../../../assets/invader.tga 56px 152px 79px 175px;
-	background-center-image: ../../../assets/invader.tga stretch 56px 175px 79px 175px;
-	background-bottom-image: ../../../assets/invader.tga 56px 176px 79px 198px;
+	decorator: tiled-vertical( sliderbar-t, sliderbar-c, sliderbar-b );
 }
 
 scrollbarvertical sliderbar:hover
 {
-	background-top-image-s: 80px 103px;
-	background-center-image-s: 80px 103px;
-	background-bottom-image-s: 80px 103px;
+	decorator: tiled-vertical( sliderbar-hover-t, sliderbar-hover-c, sliderbar-hover-b );
 }
 
 scrollbarvertical sliderbar:active
 {
-	background-top-image-s: 104px 127px;
-	background-center-image-s: 104px 127px;
-	background-bottom-image-s: 104px 127px;
+	decorator: tiled-vertical( sliderbar-active-t, sliderbar-active-c, sliderbar-active-b );
 }
 
 scrollbarvertical sliderarrowdec,
@@ -105,24 +132,26 @@ scrollbarvertical sliderarrowinc
 
 scrollbarvertical sliderarrowdec
 {
-	icon-decorator: image;
-	icon-image: ../../../assets/invader.tga 0px 152px 27px 176px;
+	decorator: image( sliderarrowdec );
+}
+scrollbarvertical sliderarrowdec:hover
+{
+	decorator: image( sliderarrowdec-hover );
+}
+scrollbarvertical sliderarrowdec:active
+{
+	decorator: image( sliderarrowdec-active );
 }
 
 scrollbarvertical sliderarrowinc
 {
-	icon-decorator: image;
-	icon-image: ../../../assets/invader.tga 28px 152px 55px 176px;
+	decorator: image( sliderarrowinc );
 }
-
-scrollbarvertical sliderarrowdec:hover,
 scrollbarvertical sliderarrowinc:hover
 {
-	icon-image-t: 177px 201px;
+	decorator: image( sliderarrowinc-hover );
 }
-
-scrollbarvertical sliderarrowdec:active,
 scrollbarvertical sliderarrowinc:active
 {
-	icon-image-t: 202px 226px;
+	decorator: image( sliderarrowinc-active );
 }

+ 52 - 26
Samples/tutorial/datagrid_tree/data/tutorial.rml

@@ -3,6 +3,31 @@
 	<link type="text/template" href="template.rml"/>
 	<title>Datagrid Tutorial</title>
 	<style>
+		@spritesheet datagrid-theme
+		{
+			src: ../../../assets/invader.tga;
+			
+			datagridbody-tl: 281px 275px 11px 9px;
+			datagridbody-t:  292px 275px 1px 9px;
+			datagridbody-tr: 294px 275px 11px 9px;
+			datagridbody-l:  281px 283px 11px 1px;
+			datagridbody-c:  292px 283px 1px 1px;
+			datagridbody-bl: 281px 285px 11px 11px;
+			datagridbody-b:  292px 285px 1px 11px;
+			datagridbody-br: 294px 285px 11px 11px;
+			
+			datagridheader-l: 127px 192px 16px 31px;
+			datagridheader-c: 143px 192px 2px 31px;
+			datagridheader-r: 145px 192px 15px 31px;
+			
+			datagridexpand: 3px 232px 17px 17px;
+			datagridexpand-hover: 21px 232px 17px 17px;
+			datagridexpand-active: 39px 232px 17px 17px;
+			datagridexpand-collapsed: 3px 250px 17px 17px;
+			datagridexpand-collapsed-hover: 21px 250px 17px 17px;
+			datagridexpand-collapsed-active: 39px 250px 17px 17px;
+		}
+	
 		body
 		{
 			width: 400px;
@@ -17,23 +42,22 @@
 			width: 64px;
 			height: 16px;
 			
-			defender-decorator: defender;
-			defender-image-src: ../../../assets/high_scores_defender.tga;
+			decorator: defender( ../../../assets/high_scores_defender.tga );
 		}
 		
 		defender.alien_1
 		{
-			defender-image-src: ../../../assets/high_scores_alien_1.tga;
+			decorator: defender( ../../../assets/high_scores_alien_1.tga );
 		}
 		
 		defender.alien_2
 		{
-			defender-image-src: ../../../assets/high_scores_alien_2.tga;
+			decorator: defender( ../../../assets/high_scores_alien_2.tga );
 		}
 		
 		defender.alien_3
 		{
-			defender-image-src: ../../../assets/high_scores_alien_3.tga;
+			decorator: defender( ../../../assets/high_scores_alien_3.tga );
 		}
 		
 		datagridheader
@@ -42,10 +66,7 @@
 			height: 25px;
 			padding: 5px 10px 0px 10px;
 		
-			background-decorator: tiled-horizontal;
-			background-left-image: ../../../assets/invader.tga 127px 192px 143px 223px;
-			background-center-image: ../../../assets/invader.tga stretch 143px 192px 145px 223px;
-			background-right-image: ../../../assets/invader.tga 145px 192px 160px 223px;
+			decorator: tiled-horizontal( datagridheader-l, datagridheader-c, datagridheader-r );
 		}
 		
 		datagridbody
@@ -57,15 +78,11 @@
 			margin-right: 3px;
 			padding: 0px 4px 4px 4px;
 			
-			background-decorator: tiled-box;
-			background-top-left-image: ../../../assets/invader.tga 281px 275px 292px 284px;
-			background-top-right-image: ../../../assets/invader.tga 294px 275px 305px 284px;
-			background-top-image: ../../../assets/invader.tga stretch 292px 275px 293px 284px;
-			background-bottom-left-image: ../../../assets/invader.tga 281px 285px 292px 296px;
-			background-bottom-right-image: ../../../assets/invader.tga 294px 285px 305px 296px;
-			background-bottom-image: ../../../assets/invader.tga stretch 292px 285px 293px 296px;
-			background-left-image: ../../../assets/invader.tga stretch 281px 283px 292px 284px;
-			background-center-image: ../../../assets/invader.tga stretch 292px 283px 293px 284px;
+			decorator: tiled-box(
+				datagridbody-tl, datagridbody-t, datagridbody-tr, 
+				datagridbody-l, datagridbody-c, auto,  /* auto mirrors left */
+				datagridbody-bl, datagridbody-b, datagridbody-br
+			);
 		}
 		
 		datagrid datagridrow:nth-child(even)
@@ -81,23 +98,32 @@
 			height: 17px;
 			width: 17px;
 			
-			icon-decorator: image;
-			icon-image: ../../../assets/invader.tga 3px 232px 20px 249px;
+			decorator: image( datagridexpand );
 		}
-		
+
 		datagridexpand:hover
 		{
-			icon-image-s: 21px 38px;
+			decorator: image( datagridexpand-hover );
 		}
-		
+
 		datagridexpand:active
 		{
-			icon-image-s: 39px 56px;
+			decorator: image( datagridexpand-active  );
 		}
-		
+
 		datagridexpand.collapsed
 		{
-			icon-image-t: 250px 267px;
+			decorator: image( datagridexpand-collapsed );
+		}
+
+		datagridexpand.collapsed:hover
+		{
+			decorator: image( datagridexpand-collapsed-hover );
+		}
+
+		datagridexpand.collapsed:active
+		{
+			decorator: image( datagridexpand-collapsed-active  );
 		}
 	</style>
 </head>

+ 6 - 7
Samples/tutorial/datagrid_tree/src/DecoratorInstancerDefender.cpp

@@ -16,7 +16,8 @@
 
 DecoratorInstancerDefender::DecoratorInstancerDefender()
 {
-	RegisterProperty("image-src", "").AddParser("string");
+	id_image_src = RegisterProperty("image-src", "").AddParser("string").GetId();
+	RegisterShorthand("decorator", "image-src", Rocket::Core::ShorthandType::FallThrough);
 }
 
 DecoratorInstancerDefender::~DecoratorInstancerDefender()
@@ -24,20 +25,18 @@ DecoratorInstancerDefender::~DecoratorInstancerDefender()
 }
 
 // Instances a decorator given the property tag and attributes from the RCSS file.
-Rocket::Core::Decorator* DecoratorInstancerDefender::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties)
+std::shared_ptr<Rocket::Core::Decorator> DecoratorInstancerDefender::InstanceDecorator(const Rocket::Core::String& ROCKET_UNUSED_PARAMETER(name), const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface)
 {
 	ROCKET_UNUSED(name);
 
-	const Rocket::Core::Property* image_source_property = properties.GetProperty("image-src");
+	const Rocket::Core::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rocket::Core::String image_source = image_source_property->Get< Rocket::Core::String >();
 
-	DecoratorDefender* decorator = new DecoratorDefender();
+	auto decorator = std::make_shared<DecoratorDefender>();
 	if (decorator->Initialise(image_source, image_source_property->source))
 		return decorator;
 
-	decorator->RemoveReference();
-	ReleaseDecorator(decorator);
-	return NULL;
+	return nullptr;
 }
 
 // Releases the given decorator.

+ 9 - 4
Samples/tutorial/datagrid_tree/src/DecoratorInstancerDefender.h

@@ -26,16 +26,21 @@ public:
 	virtual ~DecoratorInstancerDefender();
 
 	/// Instances a decorator given the property tag and attributes from the RCSS file.
-	/// @param name The type of decorator desired. For example, "background-decorator: simple;" is declared as type "simple".
-	/// @param properties All RCSS properties associated with the decorator.
-	/// @return The decorator if it was instanced successful, NULL if an error occured.
-	Rocket::Core::Decorator* InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties);
+	/// @param[in] name The type of decorator desired. For example, "decorator: simple(...);" is declared as type "simple".
+	/// @param[in] properties All RCSS properties associated with the decorator.
+	/// @param[in] interface An interface for querying the active style sheet.
+	/// @return A shared_ptr to the decorator if it was instanced successfully.
+	std::shared_ptr<Rocket::Core::Decorator> InstanceDecorator(const Rocket::Core::String& name, const Rocket::Core::PropertyDictionary& properties, const Rocket::Core::DecoratorInstancerInterface& interface) override;
+
 	/// Releases the given decorator.
 	/// @param decorator Decorator to release. This is guaranteed to have been constructed by this instancer.
 	void ReleaseDecorator(Rocket::Core::Decorator* decorator);
 
 	/// Releases the instancer.
 	void Release();
+
+private:
+	Rocket::Core::PropertyId id_image_src;
 };
 
 #endif

+ 1 - 3
Samples/tutorial/datagrid_tree/src/main.cpp

@@ -98,9 +98,7 @@ int main(int ROCKET_UNUSED_PARAMETER(argc), char** ROCKET_UNUSED_PARAMETER(argv)
 	Shell::LoadFonts("../../assets/");
 
 	// Load the defender decorator.
-	Rocket::Core::DecoratorInstancer* decorator_instancer = Rocket::Core::Factory::RegisterDecoratorInstancer("defender", new DecoratorInstancerDefender());
-	if (decorator_instancer != NULL)
-		decorator_instancer->RemoveReference();
+	Rocket::Core::Factory::RegisterDecoratorInstancer("defender", std::make_unique<DecoratorInstancerDefender>());
 
 	// Add the ship formatter.
 	HighScoresShipFormatter ship_formatter;

+ 20 - 9
Samples/tutorial/template/data/tutorial.rcss

@@ -1,3 +1,18 @@
+@spritesheet theme 
+{
+	src: ../../../assets/invader.tga;
+
+	window-tl: 0px 0px 133px 140px;
+	window-t:  134px 0px 1px 140px;
+	window-tr: 136px 0px 10px 140px;
+	window-l:  0px 139px 10px 1px;
+	window-c:  11px 139px 1px 1px;
+	window-r:  10px 139px -10px 1px; /* mirrored left */
+	window-bl: 0px 140px 11px 11px;
+	window-b:  11px 140px 1px 11px;
+	window-br: 136px 140px 10px 11px;
+}
+
 body
 {
 	font-family: Delicious;
@@ -9,15 +24,11 @@ body
 
 body.window
 {
-	background-decorator: tiled-box;
-	background-top-left-image: ../../../assets/invader.tga 0px 0px 133px 140px;
-	background-top-right-image: ../../../assets/invader.tga 136px 0px 146px 140px;
-	background-top-image: ../../../assets/invader.tga stretch 134px 0px 135px 140px;
-	background-bottom-left-image: ../../../assets/invader.tga 0px 140px 11px 151px;
-	background-bottom-right-image: ../../../assets/invader.tga 136px 140px 146px 151px;
-	background-bottom-image: ../../../assets/invader.tga stretch 11px 140px 12px 151px;
-	background-left-image: ../../../assets/invader.tga stretch 0px 139px 10px 140px;
-	background-center-image: ../../../assets/invader.tga stretch 11px 139px 12px 140px;
+	decorator: tiled-box(
+		window-tl, window-t, window-tr, 
+		window-l, window-c, window-r,
+		window-bl, window-b, window-br
+	);
 }
 
 div

+ 1 - 2
Samples/tutorial/tutorial_drag/data/tutorial.rcss

@@ -16,8 +16,7 @@ icon
     padding: 60px 10px 0px 10px;
     margin: 10px;
     
-    background-decorator: image;
-    background-image: ../../../assets/present.tga 0px 0px 100px 100px;
+    decorator: image( ../../../assets/present.tga 0px 0px 100px 100px );
     
     font-size: 12px;
     text-align: center;

+ 2 - 2
Samples/tutorial/tutorial_drag/src/Inventory.cpp

@@ -8,8 +8,8 @@ Inventory::Inventory(const Rocket::Core::String& title, const Rocket::Core::Vect
 	if (document != NULL)
 	{
 		document->GetElementById("title")->SetInnerRML(title);
-		document->SetProperty("left", Rocket::Core::Property(position.x, Rocket::Core::Property::PX));
-		document->SetProperty("top", Rocket::Core::Property(position.y, Rocket::Core::Property::PX));
+		document->SetProperty(Rocket::Core::PropertyId::Left, Rocket::Core::Property(position.x, Rocket::Core::Property::PX));
+		document->SetProperty(Rocket::Core::PropertyId::Top, Rocket::Core::Property(position.y, Rocket::Core::Property::PX));
 		document->Show();
 	}
 }

+ 8 - 7
Source/Controls/ElementDataGrid.cpp

@@ -45,24 +45,25 @@ ElementDataGrid::ElementDataGrid(const Rocket::Core::String& tag) : Core::Elemen
 
 	// Create the row for the column headers:
 	header = static_cast< ElementDataGridRow* >(Core::Factory::InstanceElement(this, "#rktctl_datagridrow", "datagridheader", attributes));
-	header->SetProperty("display", Core::Property(Core::Style::Display::Block));
+	header->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::Block));
 	header->Initialise(this);
 	AppendChild(header);
 	header->RemoveReference();
 
 	body = Core::Factory::InstanceElement(this, "*", "datagridbody", attributes);
-	body->SetProperty("display", Core::Property(Core::Style::Display::None));
-	body->SetProperty("width", Core::Property(Core::Style::Width::Auto));
+	body->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::None));
+	body->SetProperty(Core::PropertyId::Width, Core::Property(Core::Style::Width::Auto));
 	AppendChild(body);
 	body->RemoveReference();
 
 	body_visible = false;
 
 	root = static_cast< ElementDataGridRow* >(Core::Factory::InstanceElement(this, "#rktctl_datagridrow", "datagridroot", attributes));
-	root->SetProperty("display", Core::Property(Core::Style::Display::None));
+	root->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::None));
 	root->Initialise(this);
 
-	SetProperty("overflow", Core::Property(Core::Style::Overflow::Auto));
+	SetProperty(Core::PropertyId::OverflowX, Core::Property(Core::Style::Overflow::Auto));
+	SetProperty(Core::PropertyId::OverflowY, Core::Property(Core::Style::Overflow::Auto));
 
 	new_data_source = "";
 }
@@ -108,7 +109,7 @@ void ElementDataGrid::AddColumn(const Rocket::Core::String& fields, const Rocket
 	// The header elements are added to the header row at the top of the table.
 	if (header_element)
 	{
-		header_element->SetProperty("display", Core::Property(Core::Style::Display::InlineBlock));
+		header_element->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::InlineBlock));
 
 		// Push all the width properties from the column onto the header element.
 		Rocket::Core::String width = header_element->GetAttribute<Rocket::Core::String>("width", "100%");
@@ -241,7 +242,7 @@ void ElementDataGrid::OnUpdate()
 	
 	if (!body_visible && (!any_new_children || root->GetNumLoadedChildren() >= GetAttribute("min-rows", 0)))
 	{
-		body->SetProperty("display", Core::Property(Core::Style::Display::Block));
+		body->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::Block));
 		body_visible = true;
 	}
 }

+ 1 - 1
Source/Controls/ElementDataGridCell.cpp

@@ -52,7 +52,7 @@ void ElementDataGridCell::Initialise(int _column, Core::Element* _header)
 	{
 		header->AddReference();
 		if(auto p = header->GetLocalProperty("width"))
-			SetProperty("width", *p);
+			SetProperty(Core::PropertyId::Width, *p);
 	}
 }
 

+ 6 - 6
Source/Controls/ElementDataGridRow.cpp

@@ -53,8 +53,8 @@ ElementDataGridRow::ElementDataGridRow(const Rocket::Core::String& tag) : Core::
 	dirty_children = false;
 	row_expanded = true;
 
-	SetProperty("white-space", Core::Property(Core::Style::WhiteSpace::Nowrap));
-	SetProperty("display", Core::Property(Core::Style::Display::InlineBlock));
+	SetProperty(Core::PropertyId::WhiteSpace, Core::Property(Core::Style::WhiteSpace::Nowrap));
+	SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::InlineBlock));
 }
 
 ElementDataGridRow::~ElementDataGridRow()
@@ -85,7 +85,7 @@ void ElementDataGridRow::Initialise(ElementDataGrid* _parent_grid, ElementDataGr
 	{
 		ElementDataGridCell* cell = dynamic_cast< ElementDataGridCell* >(Core::Factory::InstanceElement(this, "#rktctl_datagridcell", "datagridcell", cell_attributes));
 		cell->Initialise(i, header_row->GetChild(i));
-		cell->SetProperty("display", Core::Property(Core::Style::Display::InlineBlock));
+		cell->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::InlineBlock));
 		AppendChild(cell);
 		cell->RemoveReference();
 	}
@@ -386,7 +386,7 @@ void ElementDataGridRow::AddChildren(int first_row_added, int num_rows_added)
 
 			if (!row_expanded)
 			{
-				new_row->SetProperty("display", Core::Property(Core::Style::Display::None));
+				new_row->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::None));
 			}
 		}
 
@@ -674,7 +674,7 @@ void ElementDataGridRow::DirtyRow()
 // Sets this row's child rows to be visible.
 void ElementDataGridRow::Show()
 {
-	SetProperty("display", Core::Property(Core::Style::Display::InlineBlock));
+	SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::InlineBlock));
 
 	if (row_expanded)
 	{
@@ -688,7 +688,7 @@ void ElementDataGridRow::Show()
 // Sets this row's children to be invisible.
 void ElementDataGridRow::Hide()
 {
-	SetProperty("display", Core::Property(Core::Style::Display::None));
+	SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::None));
 
 	for (size_t i = 0; i < children.size(); i++)
 	{

+ 2 - 2
Source/Controls/ElementFormControl.cpp

@@ -33,7 +33,7 @@ namespace Controls {
 
 ElementFormControl::ElementFormControl(const Rocket::Core::String& tag) : Core::Element(tag)
 {
-	SetProperty("tab-index", Core::Property(Core::Style::TabIndex::Auto));
+	SetProperty(Core::PropertyId::TabIndex, Core::Property(Core::Style::TabIndex::Auto));
 }
 
 ElementFormControl::~ElementFormControl()
@@ -87,7 +87,7 @@ void ElementFormControl::OnAttributeChange(const Core::ElementAttributes& change
 		// events (when originating from user inputs, see Context) to reach the element.
 		if (is_disabled)
 		{
-			SetProperty("focus", Core::Property(Core::Style::Focus::None));
+			SetProperty(Core::PropertyId::Focus, Core::Property(Core::Style::Focus::None));
 			Blur();
 		}
 		else

+ 7 - 6
Source/Controls/ElementFormControlTextArea.cpp

@@ -39,8 +39,9 @@ ElementFormControlTextArea::ElementFormControlTextArea(const Rocket::Core::Strin
 {
 	widget = new WidgetTextInputMultiLine(this);
 
-	SetProperty("overflow", Core::Property(Core::Style::Overflow::Auto));
-	SetProperty("white-space", Core::Property(Core::Style::WhiteSpace::Prewrap));
+	SetProperty(Core::PropertyId::OverflowX, Core::Property(Core::Style::Overflow::Auto));
+	SetProperty(Core::PropertyId::OverflowY, Core::Property(Core::Style::Overflow::Auto));
+	SetProperty(Core::PropertyId::WhiteSpace, Core::Property(Core::Style::WhiteSpace::Prewrap));
 }
 
 ElementFormControlTextArea::~ElementFormControlTextArea()
@@ -151,9 +152,9 @@ void ElementFormControlTextArea::OnAttributeChange(const Core::ElementAttributes
 	if (changed_attributes.find("wrap") != changed_attributes.end())
 	{
 		if (GetWordWrap())
-			SetProperty("white-space", Core::Property(Core::Style::WhiteSpace::Prewrap));
+			SetProperty(Core::PropertyId::WhiteSpace, Core::Property(Core::Style::WhiteSpace::Prewrap));
 		else
-			SetProperty("white-space", Core::Property(Core::Style::WhiteSpace::Pre));
+			SetProperty(Core::PropertyId::WhiteSpace, Core::Property(Core::Style::WhiteSpace::Pre));
 	}
 
 	if (changed_attributes.find("rows") != changed_attributes.end() ||
@@ -172,8 +173,8 @@ void ElementFormControlTextArea::OnPropertyChange(const Core::PropertyNameList&
 {
 	ElementFormControl::OnPropertyChange(changed_properties);
 
-	if (changed_properties.find("color") != changed_properties.end() ||
-		changed_properties.find("background-color") != changed_properties.end())
+	if (changed_properties.find(Core::PropertyId::Color) != changed_properties.end() ||
+		changed_properties.find(Core::PropertyId::BackgroundColor) != changed_properties.end())
 		widget->UpdateSelectionColours();
 }
 

+ 5 - 5
Source/Controls/ElementTabSet.cpp

@@ -124,9 +124,9 @@ void ElementTabSet::SetActiveTab(int tab_index)
 		Core::Element* new_window = windows->GetChild(tab_index);
 
 		if (old_window)
-			old_window->SetProperty("display", Core::Property(Core::Style::Display::None));
+			old_window->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::None));
 		if (new_window)
-			new_window->SetProperty("display", Core::Property(Core::Style::Display::InlineBlock));
+			new_window->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::InlineBlock));
 
 		active_tab = tab_index;
 
@@ -178,7 +178,7 @@ void ElementTabSet::OnChildAdd(Core::Element* child)
 	if (child->GetParentNode() == GetChildByTag("tabs"))
 	{
 		// Set up the new button and append it
-		child->SetProperty("display", Core::Property(Core::Style::Display::InlineBlock));
+		child->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::InlineBlock));
 		child->AddEventListener(Core::EventId::Click, this);
 
 		if (child->GetParentNode()->GetChild(active_tab) == child)
@@ -188,11 +188,11 @@ void ElementTabSet::OnChildAdd(Core::Element* child)
 	if (child->GetParentNode() == GetChildByTag("panels"))
 	{
 		// Hide the new tab window
-		child->SetProperty("display", Core::Property(Core::Style::Display::None));
+		child->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::None));
 		
 		// Make the new element visible if its the active tab
 		if (child->GetParentNode()->GetChild(active_tab) == child)
-			child->SetProperty("display", Core::Property(Core::Style::Display::InlineBlock));
+			child->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::InlineBlock));
 	}
 }
 

+ 2 - 2
Source/Controls/ElementTextSelection.cpp

@@ -55,8 +55,8 @@ void ElementTextSelection::OnPropertyChange(const Rocket::Core::PropertyNameList
 		return;
 
 	// Check for a colour change.
-	if (changed_properties.find("color") != changed_properties.end() ||
-		changed_properties.find("background-color") != changed_properties.end())
+	if (changed_properties.find(Core::PropertyId::Color) != changed_properties.end() ||
+		changed_properties.find(Core::PropertyId::BackgroundColor) != changed_properties.end())
 	{
 		widget->UpdateSelectionColours();
 	}

+ 2 - 2
Source/Controls/InputTypeText.cpp

@@ -98,8 +98,8 @@ bool InputTypeText::OnAttributeChange(const Core::ElementAttributes& changed_att
 // Called when properties on the control are changed.
 void InputTypeText::OnPropertyChange(const Core::PropertyNameList& changed_properties)
 {
-	if (changed_properties.find("color") != changed_properties.end() ||
-		changed_properties.find("background-color") != changed_properties.end())
+	if (changed_properties.find(Core::PropertyId::Color) != changed_properties.end() ||
+		changed_properties.find(Core::PropertyId::BackgroundColor) != changed_properties.end())
 		widget->UpdateSelectionColours();
 }
 

+ 9 - 8
Source/Controls/WidgetDropDown.cpp

@@ -52,11 +52,12 @@ WidgetDropDown::WidgetDropDown(ElementFormControl* element)
 	value_element = Core::Factory::InstanceElement(element, "*", "selectvalue", Rocket::Core::XMLAttributes());
 	selection_element = Core::Factory::InstanceElement(parent_element, "*", "selectbox", Rocket::Core::XMLAttributes());
 
-	value_element->SetProperty("overflow", Core::Property(Core::Style::Overflow::Hidden));
+	value_element->SetProperty(Core::PropertyId::OverflowX, Core::Property(Core::Style::Overflow::Hidden));
+	value_element->SetProperty(Core::PropertyId::OverflowY, Core::Property(Core::Style::Overflow::Hidden));
 
-	selection_element->SetProperty("visibility", Core::Property(Core::Style::Visibility::Hidden));
-	selection_element->SetProperty("z-index", Core::Property(1.0f, Core::Property::NUMBER));
-	selection_element->SetProperty("clip", Core::Property(Core::Style::Clip::None));
+	selection_element->SetProperty(Core::PropertyId::Visibility, Core::Property(Core::Style::Visibility::Hidden));
+	selection_element->SetProperty(Core::PropertyId::ZIndex, Core::Property(1.0f, Core::Property::NUMBER));
+	selection_element->SetProperty(Core::PropertyId::Clip, Core::Property(Core::Style::Clip::None));
 
 	parent_element->AddEventListener(Core::EventId::Click, this, true);
 	parent_element->AddEventListener(Core::EventId::Blur, this);
@@ -222,8 +223,8 @@ int WidgetDropDown::AddOption(const Rocket::Core::String& rml, const Rocket::Cor
 	Core::Element* element = Core::Factory::InstanceElement(selection_element, "*", "option", Rocket::Core::XMLAttributes());
 
 	// Force to block display and inject the RML. Register a click handler so we can be notified of selection.
-	element->SetProperty("display", Core::Property(Core::Style::Display::Block));
-	element->SetProperty("clip", Core::Property(Core::Style::Clip::Auto));
+	element->SetProperty(Core::PropertyId::Display, Core::Property(Core::Style::Display::Block));
+	element->SetProperty(Core::PropertyId::Clip, Core::Property(Core::Style::Clip::Auto));
 	element->SetInnerRML(rml);
 	element->AddEventListener(Core::EventId::Click, this);
 
@@ -385,13 +386,13 @@ void WidgetDropDown::ShowSelectBox(bool show)
 {
 	if (show)
 	{
-		selection_element->SetProperty("visibility", Core::Property(Core::Style::Visibility::Visible));
+		selection_element->SetProperty(Core::PropertyId::Visibility, Core::Property(Core::Style::Visibility::Visible));
 		value_element->SetPseudoClass("checked", true);
 		button_element->SetPseudoClass("checked", true);
 	}
 	else
 	{
-		selection_element->SetProperty("visibility", Core::Property(Core::Style::Visibility::Hidden));
+		selection_element->SetProperty(Core::PropertyId::Visibility, Core::Property(Core::Style::Visibility::Hidden));
 		value_element->SetPseudoClass("checked", false);
 		button_element->SetPseudoClass("checked", false);
 	}

+ 3 - 3
Source/Controls/WidgetSlider.cpp

@@ -91,7 +91,7 @@ WidgetSlider::~WidgetSlider()
 bool WidgetSlider::Initialise()
 {
 	Core::Property drag_property = Core::Property(Core::Style::Drag::Drag);
-	parent->SetProperty("drag", drag_property);
+	parent->SetProperty(Core::PropertyId::Drag, drag_property);
 
 	// Create all of our child elements as standard elements, and abort if we can't create them.
 	track = Core::Factory::InstanceElement(parent, "*", "slidertrack", Rocket::Core::XMLAttributes());
@@ -100,8 +100,8 @@ bool WidgetSlider::Initialise()
 
 	arrows[0] = Core::Factory::InstanceElement(parent, "*", "sliderarrowdec", Rocket::Core::XMLAttributes());
 	arrows[1] = Core::Factory::InstanceElement(parent, "*", "sliderarrowinc", Rocket::Core::XMLAttributes());
-	arrows[0]->SetProperty("drag", drag_property);
-	arrows[1]->SetProperty("drag", drag_property);
+	arrows[0]->SetProperty(Core::PropertyId::Drag, drag_property);
+	arrows[1]->SetProperty(Core::PropertyId::Drag, drag_property);
 
 	if (track == NULL ||
 		bar == NULL ||

+ 5 - 4
Source/Controls/WidgetTextInput.cpp

@@ -42,9 +42,10 @@ WidgetTextInput::WidgetTextInput(ElementFormControl* _parent) : internal_dimensi
 	keyboard_showed = false;
 	
 	parent = _parent;
-	parent->SetProperty("white-space", Core::Property(Core::Style::WhiteSpace::Pre));
-	parent->SetProperty("overflow", Core::Property(Core::Style::Overflow::Hidden));
-	parent->SetProperty("drag", Core::Property(Core::Style::Drag::Drag));
+	parent->SetProperty(Core::PropertyId::WhiteSpace, Core::Property(Core::Style::WhiteSpace::Pre));
+	parent->SetProperty(Core::PropertyId::OverflowX, Core::Property(Core::Style::Overflow::Hidden));
+	parent->SetProperty(Core::PropertyId::OverflowY, Core::Property(Core::Style::Overflow::Hidden));
+	parent->SetProperty(Core::PropertyId::Drag, Core::Property(Core::Style::Drag::Drag));
 	parent->SetClientArea(Rocket::Core::Box::CONTENT);
 
 	parent->AddEventListener(Core::EventId::Keydown, this, true);
@@ -163,7 +164,7 @@ void WidgetTextInput::UpdateSelectionColours()
 	}
 
 	// Set the computed text colour on the element holding the selected text.
-	selected_text_element->SetProperty("color", Rocket::Core::Property(colour, Rocket::Core::Property::COLOUR));
+	selected_text_element->SetProperty(Core::PropertyId::Color, Rocket::Core::Property(colour, Rocket::Core::Property::COLOUR));
 
 	// If the 'background-color' property has been set on the 'selection' element, use that as the
 	// background colour for the selected text. Otherwise, use the inverse of the selected text

+ 4 - 4
Source/Core/Context.cpp

@@ -50,7 +50,7 @@ Context::Context(const String& name) : name(name), dimensions(0, 0), density_ind
 	root = Factory::InstanceElement(NULL, "*", "#root", XMLAttributes());
 	root->SetId(name);
 	root->SetOffset(Vector2f(0, 0), NULL);
-	root->SetProperty(Z_INDEX, Property(0, Property::NUMBER));
+	root->SetProperty(PropertyId::ZIndex, Property(0, Property::NUMBER));
 
 	Element* element = Factory::InstanceElement(NULL, "body", "body", XMLAttributes());
 	cursor_proxy = dynamic_cast< ElementDocument* >(element);
@@ -1115,9 +1115,9 @@ void Context::CreateDragClone(Element* element)
 
 	// Set all the required properties and pseudo-classes on the clone.
 	drag_clone->SetPseudoClass("drag", true);
-	drag_clone->SetProperty("position", Property(Style::Position::Absolute));
-	drag_clone->SetProperty("left", Property(element->GetAbsoluteLeft() - element->GetBox().GetEdge(Box::MARGIN, Box::LEFT) - mouse_position.x, Property::PX));
-	drag_clone->SetProperty("top", Property(element->GetAbsoluteTop() - element->GetBox().GetEdge(Box::MARGIN, Box::TOP) - mouse_position.y, Property::PX));
+	drag_clone->SetProperty(PropertyId::Position, Property(Style::Position::Absolute));
+	drag_clone->SetProperty(PropertyId::Left, Property(element->GetAbsoluteLeft() - element->GetBox().GetEdge(Box::MARGIN, Box::LEFT) - mouse_position.x, Property::PX));
+	drag_clone->SetProperty(PropertyId::Top, Property(element->GetAbsoluteTop() - element->GetBox().GetEdge(Box::MARGIN, Box::TOP) - mouse_position.y, Property::PX));
 }
 
 // Releases the drag clone, if one exists.

+ 35 - 44
Source/Core/Decorator.cpp

@@ -29,7 +29,6 @@
 #include "../../Include/Rocket/Core/Decorator.h"
 #include "TextureDatabase.h"
 #include "TextureResource.h"
-#include "../../Include/Rocket/Core/DecoratorInstancer.h"
 #include "../../Include/Rocket/Core/PropertyDefinition.h"
 
 namespace Rocket {
@@ -37,70 +36,62 @@ namespace Core {
 
 Decorator::Decorator()
 {
-	instancer = NULL;
-	z_index = 0;
-	specificity = -1;
 }
 
 Decorator::~Decorator()
 {
 }
 
-// Sets the z-index of the decorator.
-void Decorator::SetZIndex(float _z_index)
-{
-	z_index = _z_index;
-}
-
-// Returns the decorator's z-index.
-float Decorator::GetZIndex() const
-{
-	return z_index;
-}
-
-// Sets the specificity of the decorator.
-void Decorator::SetSpecificity(int _specificity)
-{
-	specificity = _specificity;
-}
-
-// Returns the specificity of the decorator.
-int Decorator::GetSpecificity() const
-{
-	return specificity;
-}
-
-// Releases the decorator through its instancer.
-void Decorator::OnReferenceDeactivate()
-{
-	if (instancer != NULL)
-		instancer->ReleaseDecorator(this);
-}
-
 // Attempts to load a texture into the list of textures in use by the decorator.
 int Decorator::LoadTexture(const String& texture_name, const String& rcss_path)
 {
-	for (size_t i = 0; i < textures.size(); i++)
+	if (texture_name == first_texture.GetSource())
+		return 0;
+
+	for (size_t i = 0; i < additional_textures.size(); i++)
 	{
-		if (texture_name == textures[i].GetSource())
-			return (int) i;
+		if (texture_name == additional_textures[i].GetSource())
+			return (int)i + 1;
 	}
 
 	Texture texture;
 	if (!texture.Load(texture_name, rcss_path))
 		return -1;
 
-	textures.push_back(texture);
-	return (int) textures.size() - 1;
+	additional_textures.push_back(texture);
+	return (int)additional_textures.size();
+}
+
+int Decorator::AddTexture(const Texture& texture)
+{
+	if (!texture)
+		return -1;
+
+	if (!first_texture)
+		first_texture = texture;
+
+	if (first_texture == texture)
+		return 0;
+
+	auto it = std::find(additional_textures.begin(), additional_textures.end(), texture);
+	if (it != additional_textures.end())
+		return (int)(it - additional_textures.begin()) + 1;
+
+	additional_textures.push_back(texture);
+	return (int)additional_textures.size();
 }
 
 // Returns one of the decorator's previously loaded textures.
 const Texture* Decorator::GetTexture(int index) const
 {
-	if (index < 0 || index >= (int) textures.size())
-		return NULL;
-
-	return &(textures[index]);
+	if (index == 0)
+		return &first_texture;
+	
+	index -= 1;
+	if (index < 0 || index >= (int)additional_textures.size())
+		return nullptr;
+
+	return &(additional_textures[index]);
 }
 
 

+ 5 - 6
Source/Core/DecoratorInstancer.cpp

@@ -31,7 +31,7 @@
 namespace Rocket {
 namespace Core {
 
-DecoratorInstancer::DecoratorInstancer()
+DecoratorInstancer::DecoratorInstancer() : properties(10, 10)
 {
 }
 
@@ -52,15 +52,14 @@ PropertyDefinition& DecoratorInstancer::RegisterProperty(const String& property_
 }
 
 // Registers a shorthand property definition.
-bool DecoratorInstancer::RegisterShorthand(const String& shorthand_name, const String& property_names, PropertySpecification::ShorthandType type)
+ShorthandId DecoratorInstancer::RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type)
 {
 	return properties.RegisterShorthand(shorthand_name, property_names, type);
 }
 
-// Releases the instancer.
-void DecoratorInstancer::OnReferenceDeactivate()
-{
-	Release();
+
+const Sprite* DecoratorInstancerInterface::GetSprite(const String& name) const {
+	return style_sheet.GetSprite(name);
 }
 
 }

+ 0 - 64
Source/Core/DecoratorNone.h

@@ -1,64 +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 ROCKETCOREDECORATORNONE_H
-#define ROCKETCOREDECORATORNONE_H
-
-#include "../../Include/Rocket/Core/Decorator.h"
-
-namespace Rocket {
-namespace Core {
-
-/**
-	A decorator used to represent a 'none' decorator; that is, a decorator that does nothing.
-
-	@author Peter Curry
- */
-
-class DecoratorNone : public Decorator
-{
-public:
-	virtual ~DecoratorNone();
-
-	/// Called on a decorator to generate any required per-element data for a newly decorated element.
-	/// @param element[in] The newly decorated element.
-	/// @return A handle to a decorator-defined data handle, or NULL if none is needed for the element.
-	virtual DecoratorDataHandle GenerateElementData(Element* element);
-	/// Called to release element data generated by this decorator.
-	/// @param element_data[in] The element data handle to release.
-	virtual void ReleaseElementData(DecoratorDataHandle element_data);
-
-	/// Called to render the decorator on an element.
-	/// @param element[in] The element to render the decorator on.
-	/// @param element_data[in] The handle to the data generated by the decorator for the element.
-	virtual void RenderElement(Element* element, DecoratorDataHandle element_data);
-};
-
-}
-}
-
-#endif

+ 0 - 61
Source/Core/DecoratorNoneInstancer.cpp

@@ -1,61 +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 "DecoratorNoneInstancer.h"
-#include "DecoratorNone.h"
-
-namespace Rocket {
-namespace Core {
-
-DecoratorNoneInstancer::~DecoratorNoneInstancer()
-{
-}
-
-// Instances a decorator given the property tag and attributes from the RCSS file.
-Decorator* DecoratorNoneInstancer::InstanceDecorator(const String& ROCKET_UNUSED_PARAMETER(name), const PropertyDictionary& ROCKET_UNUSED_PARAMETER(properties))
-{
-	ROCKET_UNUSED(name);
-	ROCKET_UNUSED(properties);
-
-	return new DecoratorNone();
-}
-
-// Releases the given decorator.
-void DecoratorNoneInstancer::ReleaseDecorator(Decorator* decorator)
-{
-	delete decorator;
-}
-
-// Releases the instancer.
-void DecoratorNoneInstancer::Release()
-{
-	delete this;
-}
-
-}
-}

+ 0 - 63
Source/Core/DecoratorNoneInstancer.h

@@ -1,63 +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 ROCKETCOREDECORATORNONEINSTANCER_H
-#define ROCKETCOREDECORATORNONEINSTANCER_H
-
-#include "../../Include/Rocket/Core/DecoratorInstancer.h"
-
-namespace Rocket {
-namespace Core {
-
-/**
-	The instancer for the none decorator.
-
-	@author Peter Curry
- */
-
-class DecoratorNoneInstancer : public DecoratorInstancer
-{
-public:
-	virtual ~DecoratorNoneInstancer();
-
-	/// Instances a decorator given the property tag and attributes from the RCSS file.
-	/// @param name The type of decorator desired. For example, "background-decorator: simple;" is declared as type "simple".
-	/// @param properties All RCSS properties associated with the decorator.
-	/// @return The decorator if it was instanced successful, NULL if an error occured.
-	virtual Decorator* InstanceDecorator(const String& name, const PropertyDictionary& properties);
-	/// Releases the given decorator.
-	/// @param decorator Decorator to release. This is guaranteed to have been constructed by this instancer.
-	virtual void ReleaseDecorator(Decorator* decorator);
-
-	/// Releases the instancer.
-	virtual void Release();
-};
-
-}
-}
-
-#endif

+ 37 - 37
Source/Core/DecoratorTiled.cpp

@@ -48,58 +48,58 @@ static Vector2f oriented_texcoords[6][2] = {{Vector2f(0, 0), Vector2f(1, 1)},
 													   {Vector2f(1, 0), Vector2f(0, 1)},
 													   {Vector2f(0, 1), Vector2f(1, 0)}};
 
-DecoratorTiled::Tile::Tile()
+DecoratorTiled::Tile::Tile() : position(0, 0), size(1, 1)
 {
 	texture_index = -1;
 	repeat_mode = STRETCH;
 	orientation = ROTATE_0_CW;
 
-	texcoords[0].x = 0;
-	texcoords[0].y = 0;
-	texcoords[1].x = 1;
-	texcoords[1].y = 1;
-
-	texcoords_absolute[0][0] = false;
-	texcoords_absolute[0][1] = false;
-	texcoords_absolute[1][0] = false;
-	texcoords_absolute[1][1] = false;
+	position_absolute[0] = false;
+	position_absolute[1] = false;
+	size_absolute[0] = false;
+	size_absolute[1] = false;
 }
 
-struct TileDataMapCmp {
-	RenderInterface* find;
-
-	using Element = std::pair< RenderInterface*, DecoratorTiled::Tile::TileData >;
-	bool operator() (const Element& el) const {
-		return el.first == find;
-	}
-};
 
 // Calculates the tile's dimensions from the texture and texture coordinates.
 void DecoratorTiled::Tile::CalculateDimensions(Element* element, const Texture& texture)
 {
 	RenderInterface* render_interface = element->GetRenderInterface();
-	TileDataMap::iterator data_iterator = std::find_if(data.begin(), data.end(), TileDataMapCmp{ render_interface });
+	auto data_iterator = data.find(render_interface);
 	if (data_iterator == data.end())
 	{
 		TileData new_data;
-		Vector2i texture_dimensions = texture.GetDimensions(render_interface);
+		const Vector2i texture_dimensions_i = texture.GetDimensions(render_interface);
+		const Vector2f texture_dimensions((float)texture_dimensions_i.x, (float)texture_dimensions_i.y);
 
-		for (int i = 0; i < 2; i++)
+		if (texture_dimensions.x == 0 || texture_dimensions.y == 0)
 		{
-			new_data.texcoords[i] = texcoords[i];
-
-			if (texcoords_absolute[i][0] &&
-				texture_dimensions.x > 0)
-				new_data.texcoords[i].x /= texture_dimensions.x;
-			if (texcoords_absolute[i][1] &&
-				texture_dimensions.y > 0)
-				new_data.texcoords[i].y /= texture_dimensions.y;
+			new_data.size = Vector2f(0, 0);
+			new_data.texcoords[0] = Vector2f(0, 0);
+			new_data.texcoords[1] = Vector2f(0, 0);
 		}
+		else
+		{
+			// Need to scale the coordinates to normalized units and 'size' to absolute size (pixels)
+			for(int i = 0; i < 2; i++)
+			{
+				float size_relative = size[i];
+				new_data.size[i] = Math::AbsoluteValue(size[i]);
 
-		new_data.dimensions.x = Math::AbsoluteValue((new_data.texcoords[1].x * texture_dimensions.x) - (new_data.texcoords[0].x * texture_dimensions.x));
-		new_data.dimensions.y = Math::AbsoluteValue((new_data.texcoords[1].y * texture_dimensions.y) - (new_data.texcoords[0].y * texture_dimensions.y));
+				if (size_absolute[i])
+					size_relative /= texture_dimensions[i];
+				else
+					new_data.size[i] *= texture_dimensions[i];
+				
+				new_data.texcoords[0][i] = position[i];
+				if (position_absolute[i])
+					new_data.texcoords[0][i] /= texture_dimensions[i];
 
-		data.emplace_back( render_interface,  new_data );
+				new_data.texcoords[1][i] = size_relative + new_data.texcoords[0][i];
+			}
+		}
+
+		data.emplace( render_interface, new_data );
 	}
 }
 
@@ -107,11 +107,11 @@ void DecoratorTiled::Tile::CalculateDimensions(Element* element, const Texture&
 Vector2f DecoratorTiled::Tile::GetDimensions(Element* element)
 {
 	RenderInterface* render_interface = element->GetRenderInterface();
-	TileDataMap::iterator data_iterator = std::find_if(data.begin(), data.end(), TileDataMapCmp{ render_interface });
+	auto data_iterator = data.find(render_interface);
 	if (data_iterator == data.end())
 		return Vector2f(0, 0);
 
-	return data_iterator->second.dimensions;
+	return data_iterator->second.size;
 }
 
 // Generates geometry to render this tile across a surface.
@@ -125,8 +125,8 @@ void DecoratorTiled::Tile::GenerateGeometry(std::vector< Vertex >& vertices, std
 
     // Apply opacity
     quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha);
-	
-	TileDataMap::iterator data_iterator = std::find_if(data.begin(), data.end(), TileDataMapCmp{ render_interface });
+
+	auto data_iterator = data.find(render_interface);
 	if (data_iterator == data.end())
 		return;
 
@@ -216,7 +216,7 @@ void DecoratorTiled::Tile::GenerateGeometry(std::vector< Vertex >& vertices, std
 		tile_position.y = surface_origin.y + (float) tile_dimensions.y * y;
 
 		Vector2f tile_size;
-		tile_size.y = (float) (y < num_tiles[1] - 1 ? data.dimensions.y : final_tile_dimensions.y);
+		tile_size.y = (float) (y < num_tiles[1] - 1 ? data.size.y : final_tile_dimensions.y);
 
 		// Squish the texture coordinates in the y if we're clamping and this is the last in a double-tile.
 		Vector2f tile_texcoords[2];

+ 9 - 5
Source/Core/DecoratorTiled.h

@@ -101,15 +101,19 @@ public:
 
 		struct TileData
 		{
-			Vector2f dimensions;
-			Vector2f texcoords[2];
+			Vector2f size; // 'px' units
+			Vector2f texcoords[2]; // relative units
 		};
 
-		typedef std::vector< std::pair< RenderInterface*, TileData > > TileDataMap;
+		using TileDataMap = SmallUnorderedMap< RenderInterface*, TileData >;
 
 		int texture_index;
-		Vector2f texcoords[2];
-		bool texcoords_absolute[2][2];
+
+		// Position and size within the texture, absolute or relative units
+		Vector2f position, size;
+
+		// Absolute is 'px' units, otherwise relative to the dimensions of the texture
+		bool position_absolute[2], size_absolute[2];
 
 		mutable TileDataMap data;
 

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff