Jelajahi Sumber

WIP. Move ID-name mapping to PropertySpecification. Each specification has its own set of id/names, and only the main stylesheet needs to be a singleton.
Each decorator type and font-effect type has its own property id definitions, separate from the main stylesheet.

Michael Ragazzon 6 tahun lalu
induk
melakukan
bab0571267

+ 1 - 1
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);
+	bool RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type);
 
 	// Releases the instancer.
 	virtual void OnReferenceDeactivate();

+ 84 - 5
Include/Rocket/Core/PropertySpecification.h

@@ -39,6 +39,77 @@ class StyleSheetSpecification;
 class PropertyDictionary;
 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.resize(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
+		ROCKET_ASSERT((size_t)id < name_map.size());
+		name_map[(size_t)id] = name;
+		bool inserted = reverse_map.emplace(name, id).second;
+		ROCKET_ASSERT(inserted);
+	}
+
+	void AssertAllInserted(ID last_property_inserted) const {
+		ROCKET_ASSERT(name_map.size() == (size_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)
+	{
+		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)
+	{
+		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
@@ -75,17 +146,22 @@ using ShorthandItemIdList = std::vector<ShorthandItemId>;
 class ROCKETCORE_API PropertySpecification
 {
 public:
+	PropertySpecification(size_t reserve_num_properties, size_t reserve_num_shorthands);
+	~PropertySpecification();
+
 	/// Registers a 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.
 	/// @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(PropertyId id, 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] 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.
 	/// @return The list with stored property names.
@@ -99,12 +175,14 @@ 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(ShorthandId id, const String& property_names, ShorthandType type);
+	bool 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 ShorthandDefinition* GetShorthand(ShorthandId id) const;
+	const ShorthandDefinition* GetShorthand(const String& shorthand_name) const;
 
 	bool ParsePropertyDeclaration(PropertyDictionary& dictionary, PropertyId property_id, const String& property_value, const String& source_file = "", int source_line_number = 0) const;
 
@@ -119,14 +197,15 @@ public:
 	void SetPropertyDefaults(PropertyDictionary& dictionary) const;
 
 private:
-	PropertySpecification();
-	~PropertySpecification();
-
 	typedef std::vector< PropertyDefinition* > Properties;
 	typedef std::vector< ShorthandDefinition* > Shorthands;
 
 	Properties properties;
 	Shorthands shorthands;
+
+	PropertyIdNameMap property_map;
+	ShorthandIdNameMap shorthand_map;
+
 	PropertyNameList property_names;
 	PropertyNameList inherited_property_names;
 

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

@@ -36,8 +36,6 @@ namespace Rocket {
 namespace Core {
 
 class PropertyParser;
-struct ShorthandItemId;
-using ShorthandItemIdList = std::vector<ShorthandItemId>;
 
 /**
 	@author Peter Curry
@@ -62,13 +60,13 @@ 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.
 	/// @param[in] forces_layout True if a change in this property on an element will cause the element's layout to possibly change.
 	/// @return The new property definition, ready to have parsers attached.
-	static PropertyDefinition& RegisterCustomProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout = false);
+	static PropertyDefinition& RegisterProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout = false);
 	/// Returns a property definition.
 	/// @param[in] property_name The name of the desired property.
 	/// @return The appropriate property definition if it could be found, NULL otherwise.
@@ -83,12 +81,12 @@ 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 RegisterCustomShorthand(const String& shorthand_name, const String& property_names, ShorthandType type);
+	static bool 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.

+ 2 - 2
Source/Core/DecoratorInstancer.cpp

@@ -31,7 +31,7 @@
 namespace Rocket {
 namespace Core {
 
-DecoratorInstancer::DecoratorInstancer()
+DecoratorInstancer::DecoratorInstancer() : properties(10, 10)
 {
 }
 
@@ -52,7 +52,7 @@ 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)
+bool DecoratorInstancer::RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type)
 {
 	return properties.RegisterShorthand(shorthand_name, property_names, type);
 }

+ 7 - 12
Source/Core/DecoratorTiledBoxInstancer.cpp

@@ -56,19 +56,14 @@ Decorator* DecoratorTiledBoxInstancer::InstanceDecorator(const String& ROCKET_UN
 {
 	ROCKET_UNUSED(name);
 
-	DecoratorTiled::Tile tiles[9];
-	String texture_names[9];
-	String rcss_paths[9];
+	constexpr size_t num_tiles = 9;
 
-	GetTileProperties(tiles[0], texture_names[0], rcss_paths[0], properties, "top-left-image");
-	GetTileProperties(tiles[1], texture_names[1], rcss_paths[1], properties, "top-right-image");
-	GetTileProperties(tiles[2], texture_names[2], rcss_paths[2], properties, "bottom-left-image");
-	GetTileProperties(tiles[3], texture_names[3], rcss_paths[3], properties, "bottom-right-image");
-	GetTileProperties(tiles[4], texture_names[4], rcss_paths[4], properties, "left-image");
-	GetTileProperties(tiles[5], texture_names[5], rcss_paths[5], properties, "right-image");
-	GetTileProperties(tiles[6], texture_names[6], rcss_paths[6], properties, "top-image");
-	GetTileProperties(tiles[7], texture_names[7], rcss_paths[7], properties, "bottom-image");
-	GetTileProperties(tiles[8], texture_names[8], rcss_paths[8], properties, "center-image");
+	DecoratorTiled::Tile tiles[num_tiles];
+	String texture_names[num_tiles];
+	String rcss_paths[num_tiles];
+
+	for(size_t i = 0; i < num_tiles; i++)
+		GetTileProperties(i, tiles[i], texture_names[i], rcss_paths[i], properties);
 
 	DecoratorTiledBox* decorator = new DecoratorTiledBox();
 	if (decorator->Initialise(tiles, texture_names, rcss_paths))

+ 7 - 6
Source/Core/DecoratorTiledHorizontalInstancer.cpp

@@ -48,13 +48,14 @@ Decorator* DecoratorTiledHorizontalInstancer::InstanceDecorator(const String& RO
 {
 	ROCKET_UNUSED(name);
 
-	DecoratorTiled::Tile tiles[3];
-	String texture_names[3];
-	String rcss_paths[3];
+	constexpr size_t num_tiles = 3;
 
-	GetTileProperties(tiles[0], texture_names[0], rcss_paths[0], properties, "left-image");
-	GetTileProperties(tiles[1], texture_names[1], rcss_paths[1], properties, "right-image");
-	GetTileProperties(tiles[2], texture_names[2], rcss_paths[2], properties, "center-image");
+	DecoratorTiled::Tile tiles[num_tiles];
+	String texture_names[num_tiles];
+	String rcss_paths[num_tiles];
+
+	for (size_t i = 0; i < num_tiles; i++)
+		GetTileProperties(i, tiles[i], texture_names[i], rcss_paths[i], properties);
 
 	DecoratorTiledHorizontal* decorator = new DecoratorTiledHorizontal();
 	if (decorator->Initialise(tiles, texture_names, rcss_paths))

+ 1 - 1
Source/Core/DecoratorTiledImageInstancer.cpp

@@ -50,7 +50,7 @@ Decorator* DecoratorTiledImageInstancer::InstanceDecorator(const String& ROCKET_
 	String texture_name;
 	String rcss_path;
 
-	GetTileProperties(tile, texture_name, rcss_path, properties, "image");
+	GetTileProperties(0, tile, texture_name, rcss_path, properties);
 
 	DecoratorTiledImage* decorator = new DecoratorTiledImage();
 	if (decorator->Initialise(tile, texture_name, rcss_path))

+ 30 - 20
Source/Core/DecoratorTiledInstancer.cpp

@@ -39,45 +39,55 @@ DecoratorTiledInstancer::~DecoratorTiledInstancer()
 // Adds the property declarations for a tile.
 void DecoratorTiledInstancer::RegisterTileProperty(const String& name, bool register_repeat_modes)
 {
-	RegisterProperty(CreateString(32, "%s-src", name.c_str()), "").AddParser("string");
-	RegisterProperty(CreateString(32, "%s-s-begin", name.c_str()), "0").AddParser("length");
-	RegisterProperty(CreateString(32, "%s-s-end", name.c_str()), "1").AddParser("length");
-	RegisterProperty(CreateString(32, "%s-t-begin", name.c_str()), "0").AddParser("length");
-	RegisterProperty(CreateString(32, "%s-t-end", name.c_str()), "1").AddParser("length");
-	RegisterShorthand(CreateString(32, "%s-s", name.c_str()), CreateString(64, "%s-s-begin, %s-s-end", name.c_str(), name.c_str()));
-	RegisterShorthand(CreateString(32, "%s-t", name.c_str()), CreateString(64, "%s-t-begin, %s-t-end", name.c_str(), name.c_str()));
+	TilePropertyIds tile = {};
+
+	tile.src = RegisterProperty(CreateString(32, "%s-src", name.c_str()), "").AddParser("string").GetId();
+	tile.s_begin = RegisterProperty(CreateString(32, "%s-s-begin", name.c_str()), "0").AddParser("length").GetId();
+	tile.s_end = RegisterProperty(CreateString(32, "%s-s-end", name.c_str()), "1").AddParser("length").GetId();
+	tile.t_begin = RegisterProperty(CreateString(32, "%s-t-begin", name.c_str()), "0").AddParser("length").GetId();
+	tile.t_end = RegisterProperty(CreateString(32, "%s-t-end", name.c_str()), "1").AddParser("length").GetId();
+	RegisterShorthand(CreateString(32, "%s-s", name.c_str()), CreateString(64, "%s-s-begin, %s-s-end", name.c_str(), name.c_str()), ShorthandType::FallThrough);
+	RegisterShorthand(CreateString(32, "%s-t", name.c_str()), CreateString(64, "%s-t-begin, %s-t-end", name.c_str(), name.c_str()), ShorthandType::FallThrough);
 
 	if (register_repeat_modes)
 	{
-		RegisterProperty(CreateString(32, "%s-repeat", name.c_str()), "stretch")
-			.AddParser("keyword", "stretch, clamp-stretch, clamp-truncate, repeat-stretch, repeat-truncate");
-		RegisterShorthand(name, CreateString(256, "%s-src, %s-repeat, %s-s-begin, %s-t-begin, %s-s-end, %s-t-end", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()));
+		tile.repeat = RegisterProperty(CreateString(32, "%s-repeat", name.c_str()), "stretch")
+			.AddParser("keyword", "stretch, clamp-stretch, clamp-truncate, repeat-stretch, repeat-truncate")
+			.GetId();
+		RegisterShorthand(name, CreateString(256, "%s-src, %s-repeat, %s-s-begin, %s-t-begin, %s-s-end, %s-t-end", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()), ShorthandType::FallThrough);
 	}
 	else
-		RegisterShorthand(name, CreateString(256, "%s-src, %s-s-begin, %s-t-begin, %s-s-end, %s-t-end", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()));
+		RegisterShorthand(name, CreateString(256, "%s-src, %s-s-begin, %s-t-begin, %s-s-end, %s-t-end", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()), ShorthandType::FallThrough);
+
+	// @performance: Reserve number of tiles on construction
+	tile_property_ids.push_back(tile);
 }
 
 // Retrieves all the properties for a tile from the property dictionary.
-void DecoratorTiledInstancer::GetTileProperties(DecoratorTiled::Tile& tile, String& texture_name, String& rcss_path, const PropertyDictionary& properties, const String& name)
+void DecoratorTiledInstancer::GetTileProperties(size_t tile_index, DecoratorTiled::Tile& tile, String& texture_name, String& rcss_path, const PropertyDictionary& properties)
 {
-	LoadTexCoord(properties, CreateString(32, "%s-s-begin", name.c_str()), tile.texcoords[0].x, tile.texcoords_absolute[0][0]);
-	LoadTexCoord(properties, CreateString(32, "%s-t-begin", name.c_str()), tile.texcoords[0].y, tile.texcoords_absolute[0][1]);
-	LoadTexCoord(properties, CreateString(32, "%s-s-end", name.c_str()), tile.texcoords[1].x, tile.texcoords_absolute[1][0]);
-	LoadTexCoord(properties, CreateString(32, "%s-t-end", name.c_str()), tile.texcoords[1].y, tile.texcoords_absolute[1][1]);
+	ROCKET_ASSERT(tile_index < tile_property_ids.size());
+
+	const TilePropertyIds& ids = tile_property_ids[tile_index];
+
+	LoadTexCoord(properties, ids.s_begin, tile.texcoords[0].x, tile.texcoords_absolute[0][0]);
+	LoadTexCoord(properties, ids.t_begin, tile.texcoords[0].y, tile.texcoords_absolute[0][1]);
+	LoadTexCoord(properties, ids.s_end, tile.texcoords[1].x, tile.texcoords_absolute[1][0]);
+	LoadTexCoord(properties, ids.t_end, tile.texcoords[1].y, tile.texcoords_absolute[1][1]);
 
-	const Property* repeat_property = properties.GetProperty(CreateString(32, "%s-repeat", name.c_str()));
+	const Property* repeat_property = properties.GetProperty(ids.repeat);
 	if (repeat_property != NULL)
 		tile.repeat_mode = (DecoratorTiled::TileRepeatMode) repeat_property->value.Get< int >();
 
-	const Property* texture_property = properties.GetProperty(CreateString(32, "%s-src", name.c_str()));
+	const Property* texture_property = properties.GetProperty(ids.src);
 	texture_name = texture_property->Get< String >();
 	rcss_path = texture_property->source;
 }
 
 // Loads a single texture coordinate value from the properties.
-void DecoratorTiledInstancer::LoadTexCoord(const PropertyDictionary& properties, const String& name, float& tex_coord, bool& tex_coord_absolute)
+void DecoratorTiledInstancer::LoadTexCoord(const PropertyDictionary& properties, PropertyId id, float& tex_coord, bool& tex_coord_absolute)
 {
-	const Property* property = properties.GetProperty(name);
+	const Property* property = properties.GetProperty(id);
 	if (property == NULL)
 		return;
 

+ 8 - 2
Source/Core/DecoratorTiledInstancer.h

@@ -54,11 +54,17 @@ protected:
 	/// @param[out] rcss_path The path of the RCSS file that generated the texture path.
 	/// @param[in] properties The user-defined list of parameters for the decorator.
 	/// @param[in] name The name of the tile to fetch the properties for.
-	void GetTileProperties(DecoratorTiled::Tile& tile, String& texture_name, String& rcss_path, const PropertyDictionary& properties, const String& name);
+	void GetTileProperties(size_t tile_index, DecoratorTiled::Tile& tile, String& texture_name, String& rcss_path, const PropertyDictionary& properties);
 
 private:
 	// Loads a single texture coordinate value from the properties.
-	void LoadTexCoord(const PropertyDictionary& properties, const String& name, float& tex_coord, bool& tex_coord_absolute);
+	void LoadTexCoord(const PropertyDictionary& properties, PropertyId id, float& tex_coord, bool& tex_coord_absolute);
+
+	struct TilePropertyIds {
+		PropertyId src, s_begin, s_end, t_begin, t_end, repeat;
+	};
+
+	std::vector<TilePropertyIds> tile_property_ids;
 };
 
 }

+ 7 - 6
Source/Core/DecoratorTiledVerticalInstancer.cpp

@@ -48,13 +48,14 @@ Decorator* DecoratorTiledVerticalInstancer::InstanceDecorator(const String& ROCK
 {
 	ROCKET_UNUSED(name);
 
-	DecoratorTiled::Tile tiles[3];
-	String texture_names[3];
-	String rcss_paths[3];
+	constexpr size_t num_tiles = 3;
 
-	GetTileProperties(tiles[0], texture_names[0], rcss_paths[0], properties, "top-image");
-	GetTileProperties(tiles[1], texture_names[1], rcss_paths[1], properties, "bottom-image");
-	GetTileProperties(tiles[2], texture_names[2], rcss_paths[2], properties, "center-image");
+	DecoratorTiled::Tile tiles[num_tiles];
+	String texture_names[num_tiles];
+	String rcss_paths[num_tiles];
+
+	for (size_t i = 0; i < num_tiles; i++)
+		GetTileProperties(i, tiles[i], texture_names[i], rcss_paths[i], properties);
 
 	DecoratorTiledVertical* decorator = new DecoratorTiledVertical();
 	if (decorator->Initialise(tiles, texture_names, rcss_paths))

+ 6 - 4
Source/Core/Factory.cpp

@@ -349,12 +349,14 @@ Decorator* Factory::InstanceDecorator(const String& name, const PropertyDictiona
 	float z_index = 0;
 	int specificity = -1;
 
-	DecoratorInstancerMap::iterator iterator = decorator_instancers.find(name);
+	auto iterator = decorator_instancers.find(name);
 	if (iterator == decorator_instancers.end())
 		return NULL;
 
+	DecoratorInstancer* instancer = iterator->second;
+
 	// Turn the generic, un-parsed properties we've got into a properly parsed dictionary.
-	const PropertySpecification& property_specification = (*iterator).second->GetPropertySpecification();
+	const PropertySpecification& property_specification = instancer->GetPropertySpecification();
 
 	PropertyDictionary parsed_properties;
 	for (PropertyMap::const_iterator i = properties.GetProperties().begin(); i != properties.GetProperties().end(); ++i)
@@ -371,13 +373,13 @@ Decorator* Factory::InstanceDecorator(const String& name, const PropertyDictiona
 	// Set the property defaults for all unset properties.
 	property_specification.SetPropertyDefaults(parsed_properties);
 
-	Decorator* decorator = (*iterator).second->InstanceDecorator(name, parsed_properties);
+	Decorator* decorator = instancer->InstanceDecorator(name, parsed_properties);
 	if (decorator == NULL)
 		return NULL;
 
 	decorator->SetZIndex(z_index);
 	decorator->SetSpecificity(specificity);
-	decorator->instancer = (*iterator).second;
+	decorator->instancer = instancer;
 	return decorator;
 }
 

+ 2 - 2
Source/Core/FontEffectInstancer.cpp

@@ -31,7 +31,7 @@
 namespace Rocket {
 namespace Core {
 
-FontEffectInstancer::FontEffectInstancer()
+FontEffectInstancer::FontEffectInstancer() : properties(10, 10)
 {
 }
 
@@ -55,7 +55,7 @@ PropertyDefinition& FontEffectInstancer::RegisterProperty(const String& property
 }
 
 // Registers a shorthand property definition.
-bool FontEffectInstancer::RegisterShorthand(const String& shorthand_name, const String& property_names, PropertySpecification::ShorthandType type)
+bool FontEffectInstancer::RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type)
 {
 	return properties.RegisterShorthand(shorthand_name, property_names, type);
 }

+ 3 - 4
Source/Core/FontEffectOutlineInstancer.cpp

@@ -32,10 +32,9 @@
 namespace Rocket {
 namespace Core {
 
-FontEffectOutlineInstancer::FontEffectOutlineInstancer()
+FontEffectOutlineInstancer::FontEffectOutlineInstancer() : id_width(PropertyId::Invalid)
 {
-	RegisterProperty("width", "1", true)
-		.AddParser("length");
+	id_width = RegisterProperty("width", "1", true).AddParser("length").GetId();
 }
 
 FontEffectOutlineInstancer::~FontEffectOutlineInstancer()
@@ -47,7 +46,7 @@ FontEffect* FontEffectOutlineInstancer::InstanceFontEffect(const String& ROCKET_
 {
 	ROCKET_UNUSED(name);
 
-	float width = properties.GetProperty("width")->Get< float >();
+	float width = properties.GetProperty(id_width)->Get< float >();
 
 	FontEffectOutline* font_effect = new FontEffectOutline();
 	if (font_effect->Initialise(Math::RealToInteger(width)))

+ 3 - 0
Source/Core/FontEffectOutlineInstancer.h

@@ -56,6 +56,9 @@ public:
 
 	/// Releases the instancer.
 	virtual void Release();
+
+private:
+	PropertyId id_width;
 };
 
 }

+ 6 - 8
Source/Core/FontEffectShadowInstancer.cpp

@@ -32,13 +32,11 @@
 namespace Rocket {
 namespace Core {
 
-FontEffectShadowInstancer::FontEffectShadowInstancer()
+FontEffectShadowInstancer::FontEffectShadowInstancer() : offset_x(PropertyId::Invalid), offset_y(PropertyId::Invalid)
 {
-	RegisterProperty("offset-x", "0", true)
-		.AddParser("length");
-	RegisterProperty("offset-y", "0", true)
-		.AddParser("length");
-	RegisterShorthand("offset", "offset-x, offset-y");
+	offset_x = RegisterProperty("offset-x", "0", true).AddParser("length").GetId();
+	offset_y = RegisterProperty("offset-y", "0", true).AddParser("length").GetId();
+	RegisterShorthand("offset", "offset-x, offset-y", ShorthandType::FallThrough);
 }
 
 FontEffectShadowInstancer::~FontEffectShadowInstancer()
@@ -51,8 +49,8 @@ FontEffect* FontEffectShadowInstancer::InstanceFontEffect(const String& ROCKET_U
 	ROCKET_UNUSED(name);
 
 	Vector2i offset;
-	offset.x = Math::RealToInteger(properties.GetProperty("offset-x")->Get< float >());
-	offset.y = Math::RealToInteger(properties.GetProperty("offset-y")->Get< float >());
+	offset.x = Math::RealToInteger(properties.GetProperty(offset_x)->Get< float >());
+	offset.y = Math::RealToInteger(properties.GetProperty(offset_y)->Get< float >());
 
 	FontEffectShadow* font_effect = new FontEffectShadow();
 	if (font_effect->Initialise(offset))

+ 3 - 0
Source/Core/FontEffectShadowInstancer.h

@@ -56,6 +56,9 @@ public:
 
 	/// Releases the instancer.
 	virtual void Release();
+
+private:
+	PropertyId offset_x, offset_y;
 };
 
 }

+ 24 - 10
Source/Core/PropertySpecification.cpp

@@ -36,15 +36,9 @@
 namespace Rocket {
 namespace Core {
 
-PropertySpecification::PropertySpecification() :
-	// Reserve space for all defined ids and some more for custom properties
-	properties(2 * (size_t)PropertyId::NumDefinedIds, nullptr),
-	shorthands(2 * (size_t)ShorthandId::NumDefinedIds, nullptr)
+PropertySpecification::PropertySpecification(size_t reserve_num_properties, size_t reserve_num_shorthands) 
+	: properties(reserve_num_properties, nullptr), shorthands(reserve_num_shorthands, nullptr), property_map(reserve_num_properties), shorthand_map(reserve_num_shorthands)
 {
-	static bool initialized = false;
-	// Right now, we must access this as a singleton for consistency of property ids
-	ROCKET_ASSERT(!initialized);
-	initialized = true;
 }
 
 PropertySpecification::~PropertySpecification()
@@ -56,8 +50,13 @@ PropertySpecification::~PropertySpecification()
 }
 
 // Registers a property with a new definition.
-PropertyDefinition& PropertySpecification::RegisterProperty(PropertyId id, const String& default_value, bool inherited, bool forces_layout)
+PropertyDefinition& PropertySpecification::RegisterProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout, PropertyId id)
 {
+	if (id == PropertyId::Invalid)
+		id = property_map.GetOrCreateId(property_name);
+	else
+		property_map.AddPair(id, property_name);
+
 	size_t index = (size_t)id;
 	ROCKET_ASSERT(index < (size_t)INT16_MAX);
 
@@ -93,6 +92,11 @@ const PropertyDefinition* PropertySpecification::GetProperty(PropertyId id) cons
 	return properties[(size_t)id];
 }
 
+const PropertyDefinition* PropertySpecification::GetProperty(const String& property_name) const
+{
+	return GetProperty(property_map.GetId(property_name));
+}
+
 // Fetches a list of the names of all registered property definitions.
 const PropertyNameList& PropertySpecification::GetRegisteredProperties(void) const
 {
@@ -106,8 +110,13 @@ const PropertyNameList& PropertySpecification::GetRegisteredInheritedProperties(
 }
 
 // Registers a shorthand property definition.
-bool PropertySpecification::RegisterShorthand(ShorthandId id, const String& property_names, ShorthandType type)
+bool PropertySpecification::RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type, ShorthandId id)
 {
+	if (id == ShorthandId::Invalid)
+		id = shorthand_map.GetOrCreateId(shorthand_name);
+	else
+		shorthand_map.AddPair(id, shorthand_name);
+
 	StringList property_list;
 	StringUtilities::ExpandString(property_list, ToLower(property_names));
 	ShorthandItemIdList id_list;
@@ -194,6 +203,11 @@ const ShorthandDefinition* PropertySpecification::GetShorthand(ShorthandId id) c
 	return shorthands[(size_t)id];
 }
 
+const ShorthandDefinition* PropertySpecification::GetShorthand(const String& shorthand_name) const
+{
+	return GetShorthand(shorthand_map.GetId(shorthand_name));
+}
+
 bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, PropertyId property_id, const String& property_value, const String& source_file, int source_line_number) const
 {
 	// Parse as a single property.

+ 1 - 1
Source/Core/StyleSheetParser.cpp

@@ -299,7 +299,7 @@ bool StyleSheetParser::ReadProperties(PropertyDictionary& properties)
 					name = StringUtilities::StripWhitespace(name);
 					if (!name.empty())
 					{
-						Log::Message(Log::LT_WARNING, "Found name with no value parsing property declaration '%s' at %s:%d", name.c_str(), stream_file_name.c_str(), line_number);
+						Log::Message(Log::LT_WARNING, "Found name with no value while parsing property declaration '%s' at %s:%d", name.c_str(), stream_file_name.c_str(), line_number);
 						name.clear();
 					}
 				}

+ 1 - 1
Source/Core/StyleSheetParser.h

@@ -67,7 +67,7 @@ private:
 	// How far we've read through the buffer.
 	size_t parse_buffer_pos;
 
-	// The name of the file we'r parsing.
+	// The name of the file we're parsing.
 	String stream_file_name;
 	// Current line number we're parsing.
 	size_t line_number;

+ 20 - 96
Source/Core/StyleSheetSpecification.cpp

@@ -40,83 +40,13 @@ namespace Rocket {
 namespace Core {
 
 
-
-
-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.resize(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
-		ROCKET_ASSERT((size_t)id < name_map.size());
-		name_map[(size_t)id] = name;
-		bool inserted = reverse_map.emplace(name, id).second;
-		ROCKET_ASSERT(inserted);
-	}
-
-	void AssertAllInserted(ID last_property_inserted) const {
-		ROCKET_ASSERT(name_map.size() == (size_t)last_property_inserted && reverse_map.size() == (size_t)last_property_inserted);
-	}
-
-	ID GetId(const String& name)
-	{
-		auto it = reverse_map.find(name);
-		if (it != reverse_map.end())
-			return it->second;
-		return ID::Invalid;
-	}
-	const String& GetName(ID id)
-	{
-		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)
-	{
-		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() : IdNameMap(2*(size_t)PropertyId::NumDefinedIds) {}
-};
-
-class ShorthandIdNameMap : public IdNameMap<ShorthandId> {
-public:
-	ShorthandIdNameMap() : IdNameMap(2*(size_t)ShorthandId::NumDefinedIds) {}
-};
-
-static PropertyIdNameMap property_id_name_map;
-static ShorthandIdNameMap shorthand_id_name_map;
-
 static StyleSheetSpecification* instance = NULL;
 
 
 
-StyleSheetSpecification::StyleSheetSpecification()
+StyleSheetSpecification::StyleSheetSpecification() : 
+	// Reserve space for all defined ids and some more for custom properties
+	properties(2 * (size_t)PropertyId::NumDefinedIds, 2 * (size_t)ShorthandId::NumDefinedIds)
 {
 	ROCKET_ASSERT(instance == NULL);
 	instance = this;
@@ -130,14 +60,12 @@ StyleSheetSpecification::~StyleSheetSpecification()
 
 PropertyDefinition& StyleSheetSpecification::RegisterProperty(PropertyId id, const String& property_name, const String& default_value, bool inherited, bool forces_layout)
 {
-	property_id_name_map.AddPair(id, property_name);
-	return properties.RegisterProperty(id, default_value, inherited, forces_layout);
+	return properties.RegisterProperty(property_name, default_value, inherited, forces_layout, id);
 }
 
 bool StyleSheetSpecification::RegisterShorthand(ShorthandId id, const String& shorthand_name, const String& property_names, ShorthandType type)
 {
-	shorthand_id_name_map.AddPair(id, shorthand_name);
-	return properties.RegisterShorthand(id, property_names, type);
+	return properties.RegisterShorthand(shorthand_name, property_names, type, id);
 }
 
 bool StyleSheetSpecification::Initialise()
@@ -186,18 +114,16 @@ PropertyParser* StyleSheetSpecification::GetParser(const String& parser_name)
 }
 
 // Registers a property with a new definition.
-PropertyDefinition& StyleSheetSpecification::RegisterCustomProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout)
+PropertyDefinition& StyleSheetSpecification::RegisterProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout)
 {
-	PropertyId id = property_id_name_map.GetOrCreateId(property_name);
-	ROCKET_ASSERTMSG((size_t)id < (size_t)PropertyId::FirstCustomId, "Custom property name matches an internal property, please make a unique name for the given property.");
-	return instance->properties.RegisterProperty(id, default_value, inherited, forces_layout);
+	ROCKET_ASSERTMSG((size_t)instance->properties.property_map.GetId(property_name) < (size_t)PropertyId::FirstCustomId, "Custom property name matches an internal property, please make a unique name for the given property.");
+	return instance->properties.RegisterProperty(property_name, default_value, inherited, forces_layout);
 }
 
 // Returns a property definition.
 const PropertyDefinition* StyleSheetSpecification::GetProperty(const String& property_name)
 {
-	PropertyId id = property_id_name_map.GetId(property_name);
-	return instance->properties.GetProperty(id);
+	return instance->properties.GetProperty(property_name);
 }
 
 const PropertyDefinition* StyleSheetSpecification::GetProperty(PropertyId id)
@@ -217,19 +143,17 @@ const PropertyNameList & StyleSheetSpecification::GetRegisteredInheritedProperti
 }
 
 // Registers a shorthand property definition.
-bool StyleSheetSpecification::RegisterCustomShorthand(const String& shorthand_name, const String& property_names, ShorthandType type)
+bool StyleSheetSpecification::RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type)
 {
-	ROCKET_ASSERTMSG(property_id_name_map.GetId(shorthand_name) == PropertyId::Invalid, "Custom shorthand name matches a property name, please make a unique name.");
-	ShorthandId id = shorthand_id_name_map.GetOrCreateId(shorthand_name);
-	ROCKET_ASSERTMSG((size_t)id < (size_t)ShorthandId::FirstCustomId, "Custom shorthand name matches an internal shorthand, please make a unique name for the given shorthand property.");
-	return instance->properties.RegisterShorthand(id, property_names, type);
+	ROCKET_ASSERTMSG(instance->properties.property_map.GetId(shorthand_name) == PropertyId::Invalid, "Custom shorthand name matches a property name, please make a unique name.");
+	ROCKET_ASSERTMSG((size_t)instance->properties.shorthand_map.GetId(shorthand_name) < (size_t)ShorthandId::FirstCustomId, "Custom shorthand name matches an internal shorthand, please make a unique name for the given shorthand property.");
+	return instance->properties.RegisterShorthand(shorthand_name, property_names, type);
 }
 
 // Returns a shorthand definition.
 const ShorthandDefinition* StyleSheetSpecification::GetShorthand(const String& shorthand_name)
 {
-	ShorthandId id = shorthand_id_name_map.GetOrCreateId(shorthand_name);
-	return instance->properties.GetShorthand(id);
+	return instance->properties.GetShorthand(shorthand_name);
 }
 
 const ShorthandDefinition* StyleSheetSpecification::GetShorthand(ShorthandId id)
@@ -255,22 +179,22 @@ bool StyleSheetSpecification::ParsePropertyDeclaration(PropertyDictionary& dicti
 
 PropertyId StyleSheetSpecification::GetPropertyId(const String& property_name)
 {
-	return property_id_name_map.GetId(property_name);
+	return instance->properties.property_map.GetId(property_name);
 }
 
 ShorthandId StyleSheetSpecification::GetShorthandId(const String& shorthand_name)
 {
-	return shorthand_id_name_map.GetId(shorthand_name);
+	return instance->properties.shorthand_map.GetId(shorthand_name);
 }
 
 const String& StyleSheetSpecification::GetPropertyName(PropertyId id)
 {
-	return property_id_name_map.GetName(id);
+	return instance->properties.property_map.GetName(id);
 }
 
 const String& StyleSheetSpecification::GetShorthandName(ShorthandId id)
 {
-	return shorthand_id_name_map.GetName(id);
+	return instance->properties.shorthand_map.GetName(id);
 }
 
 std::vector<PropertyId> StyleSheetSpecification::GetShorthandUnderlyingProperties(ShorthandId id)
@@ -446,8 +370,8 @@ void StyleSheetSpecification::RegisterDefaultProperties()
 	RegisterProperty(PropertyId::Transition, TRANSITION, "none", false, false).AddParser(TRANSITION);
 	RegisterProperty(PropertyId::Animation, ANIMATION, "none", false, false).AddParser(ANIMATION);
 
-	property_id_name_map.AssertAllInserted(PropertyId::NumDefinedIds);
-	shorthand_id_name_map.AssertAllInserted(ShorthandId::NumDefinedIds);
+	instance->properties.property_map.AssertAllInserted(PropertyId::NumDefinedIds);
+	instance->properties.shorthand_map.AssertAllInserted(ShorthandId::NumDefinedIds);
 }
 
 }