Browse Source

Cleanup, move spritesheet to own file.

Michael Ragazzon 6 years ago
parent
commit
ad18eb571a

+ 2 - 0
Build/cmake/FileList.cmake

@@ -170,6 +170,7 @@ set(Core_PUB_HDR_FILES
     ${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
@@ -300,6 +301,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

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

@@ -69,6 +69,7 @@
 #include "PropertyParser.h"
 #include "PropertySpecification.h"
 #include "RenderInterface.h"
+#include "Spritesheet.h"
 #include "String.h"
 #include "StyleSheet.h"
 #include "StyleSheetKeywords.h"

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

@@ -117,15 +117,10 @@ public:
 	/// @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 void RegisterDecoratorInstancer(const String& name, std::unique_ptr<DecoratorInstancer> instancer);
-	/// Retrieves the property specification of a decorator registered with the factory.
-	/// @param[in] name The name of the decorator.
-	/// @return The property specification if the decorator exists, NULL otherwise.
-	static const PropertySpecification* GetDecoratorPropertySpecification(const String& name);
-	/// Attempts to instance a decorator from an instancer registered with the factory.
+	/// 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 std::shared_ptr<Decorator> InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface);
+	/// @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.

+ 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

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

@@ -28,11 +28,10 @@
 #ifndef ROCKETCORESTYLESHEET_H
 #define ROCKETCORESTYLESHEET_H
 
-#include "Dictionary.h"
 #include "ReferenceCountable.h"
-#include <set>
 #include "PropertyDictionary.h"
-#include "Texture.h"
+#include "Spritesheet.h"
+#include <set>
 
 namespace Rocket {
 namespace Core {
@@ -41,6 +40,8 @@ class Element;
 class ElementDefinition;
 class StyleSheetNode;
 class Decorator;
+class SpritesheetList;
+struct Sprite;
 struct Spritesheet;
 
 struct KeyframeBlock {
@@ -51,132 +52,13 @@ struct Keyframes {
 	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;
 };
-
-struct Sprite {
-	Rectangle rectangle;
-	const Spritesheet* sprite_sheet;
-};
-
-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 SpriteMap = UnorderedMap<String, Sprite>;
-using SpritesheetMap = UnorderedMap<String, std::shared_ptr<Spritesheet>>;
-using SpriteDefinitionList = std::vector<std::pair<String, Rectangle>>;
-
-class SpritesheetList {
-public:
-
-	bool AddSpriteSheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, const SpriteDefinitionList& sprite_definitions)
-	{
-		// Load the texture
-		Texture texture;
-		if (!texture.Load(image_source, definition_source))
-		{
-			Log::Message(Log::LT_WARNING, "Could not load image '%s' specified in spritesheet '%s' at %s:%d", image_source.c_str(), name.c_str(), definition_source.c_str(), definition_line_number);
-			return false;
-		}
-
-		auto result = spritesheet_map.emplace(name, std::make_shared<Spritesheet>(name, image_source, definition_source, definition_line_number, texture));
-		if (!result.second)
-		{
-			Log::Message(Log::LT_WARNING, "Spritesheet '%s' has the same name as another spritesheet, ignored. See %s:%d", name.c_str(), definition_source.c_str(), definition_line_number);
-			return false;
-		}
-
-		Spritesheet& spritesheet = *result.first->second;
-		StringList& sprite_names = spritesheet.sprite_names;
-		
-		// Insert all the sprites with names not already defined in the global sprite list.
-		int num_removed_sprite_names = 0;
-		for (auto& sprite_definition : sprite_definitions)
-		{
-			const String& sprite_name = sprite_definition.first;
-			const Rectangle& sprite_rectangle = sprite_definition.second;
-			auto result = sprite_map.emplace(sprite_name, Sprite{ sprite_rectangle, &spritesheet });
-			if (result.second)
-			{
-				sprite_names.push_back(sprite_name);
-			}
-			else
-			{
-				Log::Message(Log::LT_WARNING, "Sprite '%s' has the same name as an existing sprite, skipped. See %s:%d", sprite_name.c_str(), definition_source.c_str(), definition_line_number);
-			}
-		}
-
-		return true;
-	}
-
-	// Note: The pointer is invalidated whenever another sprite is added. Do not store it around.
-	const Sprite* GetSprite(const String& name) const
-	{
-		auto it = sprite_map.find(name);
-		if (it != sprite_map.end())
-			return &it->second;
-		return nullptr;
-	}
-
-	// Merge other into this
-	void Merge(const SpritesheetList& other)
-	{
-		for (auto& pair : other.spritesheet_map)
-		{
-			auto sheet_result = spritesheet_map.emplace(pair);
-			bool sheet_inserted = sheet_result.second;
-			if (sheet_inserted)
-			{
-				const String& sheet_name = sheet_result.first->first;
-				Spritesheet& sheet = *sheet_result.first->second;
-
-				// The spritesheet was succesfully added, now try to add each sprite to the global list.
-				// Each sprite name must be unique, if we fail, we must also remove the sprite from the spritesheet.
-				for (auto it = sheet.sprite_names.begin(); it != sheet.sprite_names.end(); )
-				{
-					const String& sprite_name = *it;
-					auto it_sprite = other.sprite_map.find(sprite_name);
-					bool success = false;
-					if(it_sprite != other.sprite_map.end())
-					{
-						auto sprite_result = sprite_map.emplace(*it, it_sprite->second);
-						success = sprite_result.second;
-					}
-
-					if (success)
-					{
-						++it;
-					}
-					else
-					{
-						Log::Message(Log::LT_WARNING, "Duplicate sprite name '%s' found while merging style sheets, defined in %s:%d.", sprite_name.c_str(), sheet.definition_source.c_str(), sheet.definition_line_number);
-						it = sheet.sprite_names.erase(it);
-					}
-				}
-			}
-		}
-	}
-
-
-private:
-	SpritesheetMap spritesheet_map;
-	SpriteMap sprite_map;
-};
-
 using DecoratorSpecificationMap = UnorderedMap<String, DecoratorSpecification>;
 
 
@@ -211,10 +93,10 @@ public:
 	/// 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
+	/// 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
+	/// 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
@@ -242,6 +124,7 @@ private:
 	// 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.

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

@@ -92,11 +92,6 @@ typedef Vector3< float > Vector3f;
 typedef Vector4< int > Vector4i;
 typedef Vector4< float > Vector4f;
 
-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;
-};
-
 typedef Matrix4< float, ColumnMajorStorage< float > > ColumnMajorMatrix4f;
 typedef Matrix4< float, RowMajorStorage< float > > RowMajorMatrix4f;
 typedef ColumnMajorMatrix4f Matrix4f;
@@ -108,6 +103,7 @@ class Variant;
 class Transform;
 class Decorator;
 struct Animation;
+struct Rectangle;
 enum class PropertyId : uint16_t;
 
 // Types for external interfaces.

+ 3 - 29
Source/Core/Factory.cpp

@@ -335,40 +335,14 @@ void Factory::RegisterDecoratorInstancer(const String& name, std::unique_ptr<Dec
 	decorator_instancers[lower_case_name] = std::move(instancer);
 }
 
-const PropertySpecification* Factory::GetDecoratorPropertySpecification(const String& name)
+// Retrieves a decorator instancer registered with the factory.
+DecoratorInstancer* Factory::GetDecoratorInstancer(const String& name)
 {
 	auto iterator = decorator_instancers.find(name);
 	if (iterator == decorator_instancers.end())
 		return nullptr;
 	
-	return &iterator->second->GetPropertySpecification();
-}
-
-// Attempts to instance a decorator from an instancer registered with the factory.
-std::shared_ptr<Decorator> Factory::InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface)
-{
-	auto iterator = decorator_instancers.find(name);
-	if (iterator == decorator_instancers.end())
-		return nullptr;
-
-	DecoratorInstancer& instancer = *iterator->second;
-
-	// Turn the generic, un-parsed properties we've got into a properly parsed dictionary.
-	const PropertySpecification& property_specification = instancer.GetPropertySpecification();
-
-	// Verify all properties set
-	if((size_t)properties.GetNumProperties() != property_specification.GetRegisteredProperties().size())
-	{
-		// If this occurs, call e.g. property_specification.SetPropertyDefaults(properties) before instancing decorator.
-		Log::Message(Log::LT_WARNING, "Some properties were not defined while instancing decorator '%s', make sure non-set properties are set to their default values.", name.c_str());
-		return nullptr;
-	}
-
-	std::shared_ptr<Decorator> decorator = instancer.InstanceDecorator(name, properties, interface);
-	if (!decorator)
-		return nullptr;
-
-	return decorator;
+	return iterator->second.get();
 }
 
 // Registers an instancer that will be used to instance font effects.

+ 126 - 0
Source/Core/Spritesheet.cpp

@@ -0,0 +1,126 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.h"
+#include "../../Include/Rocket/Core/Spritesheet.h"
+
+namespace Rocket {
+namespace Core {
+
+
+
+bool SpritesheetList::AddSpriteSheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, const SpriteDefinitionList& sprite_definitions)
+{
+	// Load the texture
+	Texture texture;
+	if (!texture.Load(image_source, definition_source))
+	{
+		Log::Message(Log::LT_WARNING, "Could not load image '%s' specified in spritesheet '%s' at %s:%d", image_source.c_str(), name.c_str(), definition_source.c_str(), definition_line_number);
+		return false;
+	}
+
+	auto result = spritesheet_map.emplace(name, std::make_shared<Spritesheet>(name, image_source, definition_source, definition_line_number, texture));
+	if (!result.second)
+	{
+		Log::Message(Log::LT_WARNING, "Spritesheet '%s' has the same name as another spritesheet, ignored. See %s:%d", name.c_str(), definition_source.c_str(), definition_line_number);
+		return false;
+	}
+
+	Spritesheet& spritesheet = *result.first->second;
+	StringList& sprite_names = spritesheet.sprite_names;
+
+	// Insert all the sprites with names not already defined in the global sprite list.
+	int num_removed_sprite_names = 0;
+	for (auto& sprite_definition : sprite_definitions)
+	{
+		const String& sprite_name = sprite_definition.first;
+		const Rectangle& sprite_rectangle = sprite_definition.second;
+		auto result = sprite_map.emplace(sprite_name, Sprite{ sprite_rectangle, &spritesheet });
+		if (result.second)
+		{
+			sprite_names.push_back(sprite_name);
+		}
+		else
+		{
+			Log::Message(Log::LT_WARNING, "Sprite '%s' has the same name as an existing sprite, skipped. See %s:%d", sprite_name.c_str(), definition_source.c_str(), definition_line_number);
+		}
+	}
+
+	return true;
+}
+
+
+
+const Sprite* SpritesheetList::GetSprite(const String& name) const
+{
+	auto it = sprite_map.find(name);
+	if (it != sprite_map.end())
+		return &it->second;
+	return nullptr;
+}
+
+
+void SpritesheetList::Merge(const SpritesheetList& other)
+{
+	for (auto& pair : other.spritesheet_map)
+	{
+		auto sheet_result = spritesheet_map.emplace(pair);
+		bool sheet_inserted = sheet_result.second;
+		if (sheet_inserted)
+		{
+			const String& sheet_name = sheet_result.first->first;
+			Spritesheet& sheet = *sheet_result.first->second;
+
+			// The spritesheet was succesfully added, now try to add each sprite to the global list.
+			// Each sprite name must be unique, if we fail, we must also remove the sprite from the spritesheet.
+			for (auto it = sheet.sprite_names.begin(); it != sheet.sprite_names.end(); )
+			{
+				const String& sprite_name = *it;
+				auto it_sprite = other.sprite_map.find(sprite_name);
+				bool success = false;
+				if (it_sprite != other.sprite_map.end())
+				{
+					auto sprite_result = sprite_map.emplace(*it, it_sprite->second);
+					success = sprite_result.second;
+				}
+
+				if (success)
+				{
+					++it;
+				}
+				else
+				{
+					Log::Message(Log::LT_WARNING, "Duplicate sprite name '%s' found while merging style sheets, defined in %s:%d.", sprite_name.c_str(), sheet.definition_source.c_str(), sheet.definition_line_number);
+					it = sheet.sprite_names.erase(it);
+				}
+			}
+		}
+	}
+}
+
+}
+}

+ 9 - 7
Source/Core/StyleSheet.cpp

@@ -186,32 +186,34 @@ DecoratorList StyleSheet::InstanceDecoratorsFromString(const String& decorator_s
 			const String type = StringUtilities::StripWhitespace(decorator_string.substr(0, shorthand_open));
 
 			// Check for valid decorator type
-			const PropertySpecification* specification = Factory::GetDecoratorPropertySpecification(type);
-			if (!specification)
+			DecoratorInstancer* instancer = Factory::GetDecoratorInstancer(type);
+			if (!instancer)
 			{
 				Log::Message(Log::LT_WARNING, "Decorator type '%s' not found, declared at %s:%d", type.c_str(), source_file.c_str(), source_line_number);
 				continue;
 			}
 
 			const String shorthand = decorator_string.substr(shorthand_open + 1, shorthand_close - shorthand_open - 1);
+			const PropertySpecification& specification = instancer->GetPropertySpecification();
 
-			// Parse the shorthand properties
+			// Parse the shorthand properties given by the 'decorator' shorthand property
 			PropertyDictionary properties;
-			if (!specification->ParsePropertyDeclaration(properties, "decorator", shorthand, source_file, source_line_number))
+			if (!specification.ParsePropertyDeclaration(properties, "decorator", shorthand, source_file, source_line_number))
 			{
 				Log::Message(Log::LT_WARNING, "Could not parse decorator value '%s' at %s:%d", decorator_string.c_str(), source_file.c_str(), source_line_number);
 				continue;
 			}
 
-			specification->SetPropertyDefaults(properties);
+			// Set unspecified values to their defaults
+			specification.SetPropertyDefaults(properties);
 
-			std::shared_ptr<Decorator> decorator = Factory::InstanceDecorator(type, properties, DecoratorInstancerInterface(*this));
+			std::shared_ptr<Decorator> decorator = instancer->InstanceDecorator(type, properties, DecoratorInstancerInterface(*this));
 
 			if (decorator)
 				decorator_list.emplace_back(std::move(decorator));
 			else
 			{
-				Log::Message(Log::LT_WARNING, "Decorator name '%s' could not be found in any @decorator rule, declared at %s:%d", decorator_string.c_str(), source_file.c_str(), source_line_number);
+				Log::Message(Log::LT_WARNING, "Decorator '%s' could not be instanced, declared at %s:%d", decorator_string.c_str(), source_file.c_str(), source_line_number);
 				continue;
 			}
 		}

+ 12 - 10
Source/Core/StyleSheetParser.cpp

@@ -273,38 +273,40 @@ bool StyleSheetParser::ParseDecoratorBlock(const String& at_name, DecoratorSpeci
 		return false;
 	}
 
-	// Get the property specification associated with the decorator type
-	const PropertySpecification* property_specification = Factory::GetDecoratorPropertySpecification(decorator_type);
+	// Get the instancer associated with the decorator type
+	DecoratorInstancer* decorator_instancer = Factory::GetDecoratorInstancer(decorator_type);
 	PropertyDictionary properties;
 
-	if(!property_specification)
+	if(!decorator_instancer)
 	{
 		// Type is not a declared decorator type, instead, see if it is another decorator name, then we inherit its properties.
 		auto it = decorator_map.find(decorator_type);
 		if (it != decorator_map.end())
 		{
-			// Yes, try to retrieve the property specification from the parent type, and add its property values.
-			property_specification = Factory::GetDecoratorPropertySpecification(it->second.decorator_type);
+			// Yes, try to retrieve the instancer from the parent type, and add its property values.
+			decorator_instancer = Factory::GetDecoratorInstancer(it->second.decorator_type);
 			properties = it->second.properties;
 			decorator_type = it->second.decorator_type;
 		}
 
-		// If we still don't have a property specification, we cannot continue.
-		if (!property_specification)
+		// If we still don't have an instancer, we cannot continue.
+		if (!decorator_instancer)
 		{
 			Log::Message(Log::LT_WARNING, "Invalid decorator type '%s' declared at %s:%d.", decorator_type.c_str(), stream_file_name.c_str(), line_number);
 			return false;
 		}
 	}
 
-	PropertySpecificationParser parser(properties, *property_specification);
+	const PropertySpecification& property_specification = decorator_instancer->GetPropertySpecification();
+
+	PropertySpecificationParser parser(properties, property_specification);
 	if (!ReadProperties(parser))
 		return false;
 
 	// Set non-defined properties to their defaults
-	property_specification->SetPropertyDefaults(properties);
+	property_specification.SetPropertyDefaults(properties);
 
-	std::shared_ptr<Decorator> decorator = Factory::InstanceDecorator(decorator_type, properties, DecoratorInstancerInterface(style_sheet));
+	std::shared_ptr<Decorator> decorator = decorator_instancer->InstanceDecorator(decorator_type, properties, DecoratorInstancerInterface(style_sheet));
 	if (!decorator)
 	{
 		Log::Message(Log::LT_WARNING, "Could not instance decorator of type '%s' declared at %s:%d.", decorator_type.c_str(), stream_file_name.c_str(), line_number);