Browse Source

Add PropertySource to properties and revise element info debugging

Michael Ragazzon 6 years ago
parent
commit
aa80c3b917

+ 1 - 1
Include/RmlUi/Core/Element.h

@@ -112,7 +112,7 @@ public:
 	/// Fills a string with the full address of this element.
 	/// @param[in] include_pseudo_classes True if the address is to include the pseudo-classes of the leaf element.
 	/// @return The address of the element, including its full parentage.
-	String GetAddress(bool include_pseudo_classes = false) const;
+	String GetAddress(bool include_pseudo_classes = false, bool include_parents = true) const;
 
 	/// Sets the position of this element, as a two-dimensional offset from another element.
 	/// @param[in] offset The offset (in pixels) of our primary box's top-left border corner from our offset parent's top-left border corner.

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

@@ -68,10 +68,6 @@ public:
 	const String& GetName() const;
 	const Property& GetProperty() const;
 
-	// Returns the list of pseudo classes which defines the current property, possibly empty.
-	// @todo Currently returns an empty list.
-	const PseudoClassList& GetPseudoClassList() const;
-
 private:
 	UniquePtr<PropertiesIterator> ptr;
 };

+ 9 - 4
Include/RmlUi/Core/Property.h

@@ -37,6 +37,14 @@ namespace Core {
 
 class PropertyDefinition;
 
+struct RMLUICORE_API PropertySource {
+	PropertySource(String path, int line_number, String rule_name) : path(path), line_number(line_number), rule_name(rule_name) {}
+	String path;
+	int line_number;
+	String rule_name;
+};
+
+
 /**
 	@author Peter Curry
  */
@@ -94,8 +102,6 @@ public:
 	{
 		definition = nullptr;
 		parser_index = -1;
-
-		source_line_number = 0;
 	}
 	template<typename EnumType, typename = typename std::enable_if< std::is_enum<EnumType>::value, EnumType >::type>
 	Property(EnumType value) : value(static_cast<int>(value)), unit(KEYWORD), specificity(-1) {}
@@ -120,8 +126,7 @@ public:
 	const PropertyDefinition* definition = nullptr;
 	int parser_index = -1;
 
-	String source;
-	int source_line_number = 0;
+	SharedPtr<const PropertySource> source;
 };
 
 }

+ 7 - 10
Include/RmlUi/Core/PropertyDictionary.h

@@ -48,26 +48,20 @@ class RMLUICORE_API PropertyDictionary
 public:
 	PropertyDictionary();
 
-	/// 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.
+	/// Sets a property on the dictionary. Any existing property with the same id will be overwritten.
 	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(PropertyId id);
-	/// Returns the value of the property with the requested name, if one exists.
-	/// @param[in] name The name of the desired property.
+	/// Returns the value of the property with the requested id, if one exists.
 	const Property* GetProperty(PropertyId id) const;
 
 	/// Returns the number of properties in the dictionary.
-	/// @return The number of properties in the dictionary.
 	int GetNumProperties() const;
 	/// Returns the map of properties in the dictionary.
-	/// @return The property map.
 	const PropertyMap& GetProperties() const;
 
 	/// Imports into the dictionary, and optionally defines the specificity of, potentially
-	/// un-specified properties. In the case of name conflicts, the incoming properties will
+	/// un-specified properties. In the case of id conflicts, the incoming properties will
 	/// overwrite the existing properties if their specificity (or their forced specificity)
 	/// are at least equal.
 	/// @param[in] property_dictionary The properties to import.
@@ -75,12 +69,15 @@ public:
 	void Import(const PropertyDictionary& property_dictionary, int specificity = -1);
 
 	/// Merges the contents of another fully-specified property dictionary with this one.
-	/// Properties defined in the new dictionary will overwrite those with the same name as
+	/// Properties defined in the new dictionary will overwrite those with the same id as
 	/// appropriate.
 	/// @param[in] property_dictionary The dictionary to merge.
 	/// @param[in] specificity_offset The specificities of all incoming properties will be offset by this value.
 	void Merge(const PropertyDictionary& property_dictionary, int specificity_offset = 0);
 
+	/// Set the source of all properties in the dictionary to the given one.
+	void SetSourceOfAllProperties(const SharedPtr<const PropertySource>& property_source);
+
 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

+ 3 - 3
Include/RmlUi/Core/PropertySpecification.h

@@ -106,12 +106,12 @@ public:
 	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, const String& property_name, const String& property_value) const;
 	/// Parse property declaration by ID
-	bool ParsePropertyDeclaration(PropertyDictionary& dictionary, PropertyId property_id, 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;
 	/// Parses a shorthand declaration, setting any parsed and validated properties on the given dictionary.
 	/// @return True if all properties were parsed successfully, false otherwise.
-	bool ParseShorthandDeclaration(PropertyDictionary& dictionary, ShorthandId shorthand_id, 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;
 
 	/// Sets all undefined properties in the dictionary to their defaults.
 	/// @param dictionary[in-out] The dictionary to set the default values on.

+ 2 - 2
Include/RmlUi/Core/StyleSheet.h

@@ -95,10 +95,10 @@ public:
 	SharedPtr<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;
+	DecoratorList InstanceDecoratorsFromString(const String& decorator_string_value, const PropertySource* source) const;
 
 	/// Parses the font-effect property from a string and returns a list of instanced font-effects.
-	FontEffectListPtr InstanceFontEffectsFromString(const String& font_effect_string_value, const String& source_file, int source_line_number) const;
+	FontEffectListPtr InstanceFontEffectsFromString(const String& font_effect_string_value, const PropertySource* source) const;
 
 	/// Get sprite located in any spritesheet within this stylesheet.
 	const Sprite* GetSprite(const String& name) const;

+ 1 - 1
Include/RmlUi/Core/StyleSheetSpecification.h

@@ -100,7 +100,7 @@ public:
 	/// @param[in] source_file The file where this property was declared. Used for error reporting, debugging and relative paths for referenced assets.
 	/// @param[in] line_number The location of the source file where this property was declared. Used for error reporting and debugging.
 	/// @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 bool ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value);
 
 	static PropertyId GetPropertyId(const String& property_name);
 	static ShorthandId GetShorthandId(const String& shorthand_name);

+ 4 - 1
Samples/invaders/src/DecoratorInstancerDefender.cpp

@@ -48,9 +48,12 @@ std::shared_ptr<Rml::Core::Decorator> DecoratorInstancerDefender::InstanceDecora
 
 	const Rml::Core::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rml::Core::String image_source = image_source_property->Get< Rml::Core::String >();
+	Rml::Core::String source_path;
+	if (auto & source = image_source_property->source)
+		source_path = source->path;
 
 	auto decorator = std::make_shared<DecoratorDefender>();
-	if (decorator->Initialise(image_source, image_source_property->source))
+	if (decorator->Initialise(image_source, source_path))
 		return decorator;
 	
 	return nullptr;

+ 4 - 1
Samples/luainvaders/src/DecoratorInstancerDefender.cpp

@@ -48,9 +48,12 @@ std::shared_ptr<Rml::Core::Decorator> DecoratorInstancerDefender::InstanceDecora
 
 	const Rml::Core::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rml::Core::String image_source = image_source_property->Get< Rml::Core::String >();
+	Rml::Core::String source_path;
+	if (auto & source = image_source_property->source)
+		source_path = source->path;
 
 	auto decorator = std::make_shared<DecoratorDefender>();
-	if (decorator->Initialise(image_source, image_source_property->source))
+	if (decorator->Initialise(image_source, source_path))
 		return decorator;
 
 	return nullptr;

+ 4 - 1
Samples/tutorial/datagrid/src/DecoratorInstancerDefender.cpp

@@ -31,9 +31,12 @@ std::shared_ptr<Rml::Core::Decorator> DecoratorInstancerDefender::InstanceDecora
 
 	const Rml::Core::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rml::Core::String image_source = image_source_property->Get< Rml::Core::String >();
+	Rml::Core::String source_path;
+	if (auto & source = image_source_property->source)
+		source_path = source->path;
 
 	auto decorator = std::make_shared<DecoratorDefender>();
-	if (decorator->Initialise(image_source, image_source_property->source))
+	if (decorator->Initialise(image_source, source_path))
 		return decorator;
 
 	return nullptr;

+ 4 - 1
Samples/tutorial/datagrid_tree/src/DecoratorInstancerDefender.cpp

@@ -31,9 +31,12 @@ std::shared_ptr<Rml::Core::Decorator> DecoratorInstancerDefender::InstanceDecora
 
 	const Rml::Core::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rml::Core::String image_source = image_source_property->Get< Rml::Core::String >();
+	Rml::Core::String source_path;
+	if (auto & source = image_source_property->source)
+		source_path = source->path;
 
 	auto decorator = std::make_shared<DecoratorDefender>();
-	if (decorator->Initialise(image_source, image_source_property->source))
+	if (decorator->Initialise(image_source, source_path))
 		return decorator;
 
 	return nullptr;

+ 3 - 2
Source/Core/DecoratorTiledInstancer.cpp

@@ -139,14 +139,15 @@ bool DecoratorTiledInstancer::GetTileProperties(DecoratorTiled::Tile* tiles, Tex
 			{
 				texture = previous_texture;
 			}
-			else if (texture.Load(texture_name, src_property->source))
+			else if (src_property->source && texture.Load(texture_name, src_property->source->path))
 			{
 				previous_texture_name = texture_name;
 				previous_texture = texture;
 			}
 			else
 			{
-				Log::Message(Log::LT_WARNING, "Texture name '%s' is neither a valid sprite name nor a texture file. Specified in decorator at %s:%d.", texture_name.c_str(), src_property->source.c_str(), src_property->source_line_number);
+				auto& source = src_property->source;
+				Log::Message(Log::LT_WARNING, "Texture name '%s' is neither a valid sprite name nor a texture file. Specified in decorator at %s:%d.", texture_name.c_str(), source ? source->path.c_str() : "", source ? source->line_number : -1);
 				return false;
 			}
 		}

+ 4 - 4
Source/Core/Element.cpp

@@ -351,7 +351,7 @@ const ElementDefinition* Element::GetDefinition()
 }
 
 // Fills an String with the full address of this element.
-String Element::GetAddress(bool include_pseudo_classes) const
+String Element::GetAddress(bool include_pseudo_classes, bool include_parents) const
 {
 	// Add the tag name onto the address.
 	String address(tag);
@@ -366,7 +366,7 @@ String Element::GetAddress(bool include_pseudo_classes) const
 	String classes = style->GetClassNames();
 	if (!classes.empty())
 	{
-		classes = Replace(classes, '.', ' ');
+		classes = Replace(classes, ' ', '.');
 		address += ".";
 		address += classes;
 	}
@@ -381,10 +381,10 @@ String Element::GetAddress(bool include_pseudo_classes) const
 		}
 	}
 
-	if (parent)
+	if (include_parents && parent)
 	{
 		address += " < ";
-		return address + parent->GetAddress(true);
+		return address + parent->GetAddress(true, true);
 	}
 	else
 		return address;

+ 2 - 2
Source/Core/ElementStyle.cpp

@@ -855,7 +855,7 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 				if(auto& style_sheet = element->GetStyleSheet())
 				{
 					String value = p->Get<String>();
-					values.decorator = style_sheet->InstanceDecoratorsFromString(value, p->source, p->source_line_number);
+					values.decorator = style_sheet->InstanceDecoratorsFromString(value, p->source.get());
 				}
 			}
 			break;
@@ -870,7 +870,7 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 				if (auto & style_sheet = element->GetStyleSheet())
 				{
 					String value = p->Get<String>();
-					values.font_effect = style_sheet->InstanceFontEffectsFromString(value, p->source, p->source_line_number);
+					values.font_effect = style_sheet->InstanceFontEffectsFromString(value, p->source.get());
 				}
 			}
 			break;

+ 0 - 7
Source/Core/PropertiesIterator.h

@@ -72,13 +72,6 @@ public:
 		return at_end;
 	}
 
-	// Return the list of pseudo classes which defines the current property, possibly null.
-	const PseudoClassList* GetPseudoClassList() const
-	{
-		// TODO: Not implemented
-		return nullptr;
-	}
-
 private:
 	PropertyIdSet iterated_properties;
 	PropertyIt it_style, it_style_end;

+ 0 - 10
Source/Core/PropertiesIteratorView.cpp

@@ -73,15 +73,5 @@ bool PropertiesIteratorView::AtEnd() const {
 	return ptr->AtEnd();
 }
 
-const PseudoClassList& PropertiesIteratorView::GetPseudoClassList() const
-{
-	static const PseudoClassList empty_pseudo_class_list;
-	const PseudoClassList* pseudo_list_ptr = ptr->GetPseudoClassList();
-	if (!pseudo_list_ptr)
-		return empty_pseudo_class_list;
-
-	return *pseudo_list_ptr;
-}
-
 }
 }

+ 6 - 0
Source/Core/PropertyDictionary.cpp

@@ -92,6 +92,12 @@ void PropertyDictionary::Merge(const PropertyDictionary& property_dictionary, in
 	}
 }
 
+void PropertyDictionary::SetSourceOfAllProperties(const SharedPtr<const PropertySource>& property_source)
+{
+	for (auto& p : properties)
+		p.second.source = property_source;
+}
+
 // Sets a property on the dictionary and its specificity.
 void PropertyDictionary::SetProperty(PropertyId id, const Rml::Core::Property& property, int specificity)
 {

+ 9 - 15
Source/Core/PropertySpecification.cpp

@@ -202,22 +202,22 @@ const ShorthandDefinition* PropertySpecification::GetShorthand(const String& sho
 	return GetShorthand(shorthand_map->GetId(shorthand_name));
 }
 
-bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value, const String& source_file, int source_line_number) const
+bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value) const
 {
 	// Try as a property first
 	PropertyId property_id = property_map->GetId(property_name);
 	if (property_id != PropertyId::Invalid)
-		return ParsePropertyDeclaration(dictionary, property_id, property_value, source_file, source_line_number);
+		return ParsePropertyDeclaration(dictionary, property_id, property_value);
 
 	// Then, as a shorthand
 	ShorthandId shorthand_id = shorthand_map->GetId(property_name);
 	if (shorthand_id != ShorthandId::Invalid)
-		return ParseShorthandDeclaration(dictionary, shorthand_id, property_value, source_file, source_line_number);
+		return ParseShorthandDeclaration(dictionary, shorthand_id, property_value);
 
 	return false;
 }
 
-bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, PropertyId property_id, const String& property_value, const String& source_file, int source_line_number) const
+bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, PropertyId property_id, const String& property_value) const
 {
 	// Parse as a single property.
 	const PropertyDefinition* property_definition = GetProperty(property_id);
@@ -229,8 +229,6 @@ bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& diction
 		return false;
 
 	Property new_property;
-	new_property.source = source_file;
-	new_property.source_line_number = source_line_number;
 	if (!property_definition->ParseValue(new_property, property_values[0]))
 		return false;
 	
@@ -239,7 +237,7 @@ bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& diction
 }
 
 // Parses a property declaration, setting any parsed and validated properties on the given dictionary.
-bool PropertySpecification::ParseShorthandDeclaration(PropertyDictionary& dictionary, ShorthandId shorthand_id, const String& property_value, const String& source_file, int source_line_number) const
+bool PropertySpecification::ParseShorthandDeclaration(PropertyDictionary& dictionary, ShorthandId shorthand_id, const String& property_value) const
 {
 	StringList property_values;
 	if (!ParsePropertyValues(property_values, property_value, true) || property_values.size() == 0)
@@ -286,8 +284,6 @@ bool PropertySpecification::ParseShorthandDeclaration(PropertyDictionary& dictio
 			if (!shorthand_definition->items[i].property_definition->ParseValue(new_property, property_values[value_index]))
 				return false;
 
-			new_property.source = source_file;
-			new_property.source_line_number = source_line_number;
 			dictionary.SetProperty(shorthand_definition->items[i].property_definition->GetId(), new_property);
 		}
 	}
@@ -299,9 +295,9 @@ bool PropertySpecification::ParseShorthandDeclaration(PropertyDictionary& dictio
 		{
 			const ShorthandItem& item = shorthand_definition->items[i];
 			if (item.type == ShorthandItemType::Property)
-				result &= ParsePropertyDeclaration(dictionary, item.property_id, property_value, source_file, source_line_number);
+				result &= ParsePropertyDeclaration(dictionary, item.property_id, property_value);
 			else if (item.type == ShorthandItemType::Shorthand)
-				result &= ParseShorthandDeclaration(dictionary, item.shorthand_id, property_value, source_file, source_line_number);
+				result &= ParseShorthandDeclaration(dictionary, item.shorthand_id, property_value);
 			else
 				result = false;
 		}
@@ -326,9 +322,9 @@ bool PropertySpecification::ParseShorthandDeclaration(PropertyDictionary& dictio
 		{
 			const ShorthandItem& item = shorthand_definition->items[i];
 			if (item.type == ShorthandItemType::Property)
-				result &= ParsePropertyDeclaration(dictionary, item.property_id, subvalues[i], source_file, source_line_number);
+				result &= ParsePropertyDeclaration(dictionary, item.property_id, subvalues[i]);
 			else if (item.type == ShorthandItemType::Shorthand)
-				result &= ParseShorthandDeclaration(dictionary, item.shorthand_id, subvalues[i], source_file, source_line_number);
+				result &= ParseShorthandDeclaration(dictionary, item.shorthand_id, subvalues[i]);
 			else
 				result = false;
 		}
@@ -344,8 +340,6 @@ bool PropertySpecification::ParseShorthandDeclaration(PropertyDictionary& dictio
 		for (; value_index < property_values.size() && property_index < shorthand_definition->items.size(); property_index++)
 		{
 			Property new_property;
-			new_property.source = source_file;
-			new_property.source_line_number = source_line_number;
 
 			if (!shorthand_definition->items[property_index].property_definition->ParseValue(new_property, property_values[value_index]))
 			{

+ 18 - 12
Source/Core/StyleSheet.cpp

@@ -137,7 +137,7 @@ const Sprite* StyleSheet::GetSprite(const String& name) const
 	return spritesheet_list.GetSprite(name);
 }
 
-DecoratorList StyleSheet::InstanceDecoratorsFromString(const String& decorator_string_value, const String& source_file, int source_line_number) const
+DecoratorList StyleSheet::InstanceDecoratorsFromString(const String& decorator_string_value, const PropertySource* source) const
 {
 	// Decorators are declared as
 	//   decorator: <decorator-value>[, <decorator-value> ...];
@@ -150,6 +150,9 @@ DecoratorList StyleSheet::InstanceDecoratorsFromString(const String& decorator_s
 	if (decorator_string_value.empty() || decorator_string_value == NONE)
 		return decorator_list;
 
+	const char* source_name = (source ? source->path.c_str() : "");
+	const int source_line_number = (source ? source->line_number : 0);
+
 	// Make sure we don't split inside the parenthesis since they may appear in decorator shorthands.
 	StringList decorator_string_list;
 	StringUtilities::ExpandString(decorator_string_list, decorator_string_value, ',', '(', ')');
@@ -170,7 +173,7 @@ DecoratorList StyleSheet::InstanceDecoratorsFromString(const String& decorator_s
 			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 name '%s' could not be found in any @decorator rule, declared at %s:%d", decorator_string.c_str(), source_name, source_line_number);
 		}
 		else
 		{
@@ -181,7 +184,7 @@ DecoratorList StyleSheet::InstanceDecoratorsFromString(const String& decorator_s
 			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);
+				Log::Message(Log::LT_WARNING, "Decorator type '%s' not found, declared at %s:%d", type.c_str(), source ? source->path.c_str() : "", source ? source->line_number : -1);
 				continue;
 			}
 
@@ -190,9 +193,9 @@ DecoratorList StyleSheet::InstanceDecoratorsFromString(const String& decorator_s
 
 			// 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))
 			{
-				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);
+				Log::Message(Log::LT_WARNING, "Could not parse decorator value '%s' at %s:%d", decorator_string.c_str(), source_name, source_line_number);
 				continue;
 			}
 
@@ -205,7 +208,7 @@ DecoratorList StyleSheet::InstanceDecoratorsFromString(const String& decorator_s
 				decorator_list.emplace_back(std::move(decorator));
 			else
 			{
-				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);
+				Log::Message(Log::LT_WARNING, "Decorator '%s' could not be instanced, declared at %s:%d", decorator_string.c_str(), source_name, source_line_number);
 				continue;
 			}
 		}
@@ -214,7 +217,7 @@ DecoratorList StyleSheet::InstanceDecoratorsFromString(const String& decorator_s
 	return decorator_list;
 }
 
-FontEffectListPtr StyleSheet::InstanceFontEffectsFromString(const String& font_effect_string_value, const String& source_file, int source_line_number) const
+FontEffectListPtr StyleSheet::InstanceFontEffectsFromString(const String& font_effect_string_value, const PropertySource* source) const
 {	
 	// Font-effects are declared as
 	//   font-effect: <font-effect-value>[, <font-effect-value> ...];
@@ -224,6 +227,9 @@ FontEffectListPtr StyleSheet::InstanceFontEffectsFromString(const String& font_e
 	if (font_effect_string_value.empty() || font_effect_string_value == NONE)
 		return nullptr;
 
+	const char* source_name = (source ? source->path.c_str() : "");
+	const int source_line_number = (source ? source->line_number : 0);
+
 	FontEffectList font_effect_list;
 
 	// Make sure we don't split inside the parenthesis since they may appear in decorator shorthands.
@@ -242,7 +248,7 @@ FontEffectListPtr StyleSheet::InstanceFontEffectsFromString(const String& font_e
 		if (invalid_parenthesis)
 		{
 			// We found no parenthesis, font-effects can only be declared anonymously for now.
-			Log::Message(Log::LT_WARNING, "Invalid syntax for font-effect '%s', declared at %s:%d", font_effect_string.c_str(), source_file.c_str(), source_line_number);
+			Log::Message(Log::LT_WARNING, "Invalid syntax for font-effect '%s', declared at %s:%d", font_effect_string.c_str(), source_name, source_line_number);
 		}
 		else
 		{
@@ -253,7 +259,7 @@ FontEffectListPtr StyleSheet::InstanceFontEffectsFromString(const String& font_e
 			FontEffectInstancer* instancer = Factory::GetFontEffectInstancer(type);
 			if (!instancer)
 			{
-				Log::Message(Log::LT_WARNING, "Font-effect type '%s' not found, declared at %s:%d", type.c_str(), source_file.c_str(), source_line_number);
+				Log::Message(Log::LT_WARNING, "Font-effect type '%s' not found, declared at %s:%d", type.c_str(), source_name, source_line_number);
 				continue;
 			}
 
@@ -262,9 +268,9 @@ FontEffectListPtr StyleSheet::InstanceFontEffectsFromString(const String& font_e
 
 			// Parse the shorthand properties given by the 'font-effect' shorthand property
 			PropertyDictionary properties;
-			if (!specification.ParsePropertyDeclaration(properties, "font-effect", shorthand, source_file, source_line_number))
+			if (!specification.ParsePropertyDeclaration(properties, "font-effect", shorthand))
 			{
-				Log::Message(Log::LT_WARNING, "Could not parse decorator value '%s' at %s:%d", font_effect_string.c_str(), source_file.c_str(), source_line_number);
+				Log::Message(Log::LT_WARNING, "Could not parse decorator value '%s' at %s:%d", font_effect_string.c_str(), source_name, source_line_number);
 				continue;
 			}
 
@@ -285,7 +291,7 @@ FontEffectListPtr StyleSheet::InstanceFontEffectsFromString(const String& font_e
 			}
 			else
 			{
-				Log::Message(Log::LT_WARNING, "Font-effect '%s' could not be instanced, declared at %s:%d", font_effect_string.c_str(), source_file.c_str(), source_line_number);
+				Log::Message(Log::LT_WARNING, "Font-effect '%s' could not be instanced, declared at %s:%d", font_effect_string.c_str(), source_name, source_line_number);
 				continue;
 			}
 		}

+ 2 - 2
Source/Core/StyleSheetNode.cpp

@@ -194,7 +194,7 @@ void StyleSheetNode::BuildIndexAndOptimizeProperties(StyleSheet::NodeIndex& styl
 			if (property->unit == Property::STRING)
 			{
 				const String string_value = property->Get<String>();
-				DecoratorList decorator_list = style_sheet.InstanceDecoratorsFromString(string_value, property->source, property->source_line_number);
+				DecoratorList decorator_list = style_sheet.InstanceDecoratorsFromString(string_value, property->source.get());
 
 				Property new_property = *property;
 				new_property.value = std::move(decorator_list);
@@ -209,7 +209,7 @@ void StyleSheetNode::BuildIndexAndOptimizeProperties(StyleSheet::NodeIndex& styl
 			if (property->unit == Property::STRING)
 			{
 				const String string_value = property->Get<String>();
-				FontEffectListPtr font_effects = style_sheet.InstanceFontEffectsFromString(string_value, property->source, property->source_line_number);
+				FontEffectListPtr font_effects = style_sheet.InstanceFontEffectsFromString(string_value, property->source.get());
 
 				Property new_property = *property;
 				new_property.value = std::move(font_effects);

+ 20 - 13
Source/Core/StyleSheetParser.cpp

@@ -43,7 +43,7 @@ namespace Core {
 
 class AbstractPropertyParser {
 public:
-	virtual bool Parse(const String& name, const String& value, const String& stream_file_name, int rule_line_number) = 0;
+	virtual bool Parse(const String& name, const String& value) = 0;
 };
 
 /*
@@ -58,9 +58,9 @@ private:
 public:
 	PropertySpecificationParser(PropertyDictionary& properties, const PropertySpecification& specification) : properties(properties), specification(specification) {}
 
-	bool Parse(const String& name, const String& value, const String& stream_file_name, int rule_line_number) override
+	bool Parse(const String& name, const String& value) override
 	{
-		return specification.ParsePropertyDeclaration(properties, name, value, stream_file_name, rule_line_number);
+		return specification.ParsePropertyDeclaration(properties, name, value);
 	}
 };
 
@@ -103,7 +103,7 @@ public:
 		sprite_definitions.clear();
 	}
 
-	bool Parse(const String& name, const String& value, const String& stream_file_name, int rule_line_number) override
+	bool Parse(const String& name, const String& value) override
 	{
 		static const String str_src = "src";
 		if (name == str_src)
@@ -112,7 +112,7 @@ public:
 		}
 		else
 		{
-			if (!specification.ParseShorthandDeclaration(properties, id_rectangle, value, stream_file_name, rule_line_number))
+			if (!specification.ParseShorthandDeclaration(properties, id_rectangle, value))
 				return false;
 
 			Rectangle rectangle;
@@ -345,18 +345,25 @@ int StyleSheetParser::Parse(StyleSheetNode* node, Stream* _stream, const StyleSh
 			{
 				if (token == '{')
 				{
+					const int rule_line_number = (int)line_number;
+					
 					// Read the attributes
 					PropertyDictionary properties;
 					PropertySpecificationParser parser(properties, StyleSheetSpecification::GetPropertySpecification());
 					if (!ReadProperties(parser))
 						continue;
 
-					StringList style_name_list;
-					StringUtilities::ExpandString(style_name_list, pre_token_str);
+					StringList rule_name_list;
+					StringUtilities::ExpandString(rule_name_list, pre_token_str);
+
 
 					// Add style nodes to the root of the tree
-					for (size_t i = 0; i < style_name_list.size(); i++)
-						ImportProperties(node, style_name_list[i], properties, rule_count);
+					for (size_t i = 0; i < rule_name_list.size(); i++)
+					{
+						auto source = std::make_shared<PropertySource>(stream_file_name, rule_line_number, rule_name_list[i]);
+						properties.SetSourceOfAllProperties(source);
+						ImportProperties(node, rule_name_list[i], properties, rule_count, rule_line_number);
+					}
 
 					rule_count++;
 				}
@@ -494,7 +501,7 @@ bool StyleSheetParser::ParseProperties(PropertyDictionary& parsed_properties, co
 
 bool StyleSheetParser::ReadProperties(AbstractPropertyParser& property_parser)
 {
-	int rule_line_number = (int)line_number;
+	const int rule_line_number = (int)line_number;
 	String name;
 	String value;
 
@@ -543,7 +550,7 @@ bool StyleSheetParser::ReadProperties(AbstractPropertyParser& property_parser)
 				{
 					value = StringUtilities::StripWhitespace(value);
 
-					if (!property_parser.Parse(name, value, stream_file_name, rule_line_number))
+					if (!property_parser.Parse(name, value))
 						Log::Message(Log::LT_WARNING, "Syntax error parsing property declaration '%s: %s;' in %s: %d.", name.c_str(), value.c_str(), stream_file_name.c_str(), line_number);
 
 					name.clear();
@@ -583,13 +590,13 @@ bool StyleSheetParser::ReadProperties(AbstractPropertyParser& property_parser)
 }
 
 // Updates the StyleNode tree, creating new nodes as necessary, setting the definition index
-bool StyleSheetParser::ImportProperties(StyleSheetNode* node, const String& names, const PropertyDictionary& properties, int rule_specificity)
+bool StyleSheetParser::ImportProperties(StyleSheetNode* node, const String& rule_name, const PropertyDictionary& properties, int rule_specificity, int rule_line_number)
 {
 	StyleSheetNode* tag_node = nullptr;
 	StyleSheetNode* leaf_node = node;
 
 	StringList nodes;
-	StringUtilities::ExpandString(nodes, names, ' ');
+	StringUtilities::ExpandString(nodes, rule_name, ' ');
 
 	// Create each node going down the tree
 	for (size_t i = 0; i < nodes.size(); i++)

+ 1 - 1
Source/Core/StyleSheetParser.h

@@ -84,7 +84,7 @@ private:
 	// @param names The names of the nodes
 	// @param properties The dictionary of properties
 	// @param rule_specificity The specifity of the rule
-	bool ImportProperties(StyleSheetNode* node, const String& names, const PropertyDictionary& properties, int rule_specificity);
+	bool ImportProperties(StyleSheetNode* node, const String& rule_name, const PropertyDictionary& properties, int rule_specificity, int rule_line_number);
 
 	// Attempts to parse a @keyframes block
 	bool ParseKeyframeBlock(KeyframesMap & keyframes_map, const String & identifier, const String & rules, const PropertyDictionary & properties);

+ 2 - 2
Source/Core/StyleSheetSpecification.cpp

@@ -166,9 +166,9 @@ const ShorthandDefinition* StyleSheetSpecification::GetShorthand(ShorthandId id)
 }
 
 // Parses a property declaration, setting any parsed and validated properties on the given dictionary.
-bool StyleSheetSpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value, const String& source_file, int source_line_number)
+bool StyleSheetSpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value)
 {
-	return instance->properties.ParsePropertyDeclaration(dictionary, property_name, property_value, source_file, source_line_number);
+	return instance->properties.ParsePropertyDeclaration(dictionary, property_name, property_value);
 }
 
 PropertyId StyleSheetSpecification::GetPropertyId(const String& property_name)

+ 8 - 1
Source/Debugger/CommonSource.h

@@ -62,7 +62,7 @@ h2
 }
 h3
 {
-	margin-top: 1em;
+	margin-top: 0.6em;
 	color: red;
 }
 h4
@@ -82,6 +82,13 @@ h1 .button
 {
 	z-index: 1;
 }
+h3.mark
+{
+	margin-top: 1.0em;
+	padding: 2dp;
+	color: #900;
+	background-color: #eee;
+}
 div#close_button
 {
 	margin-left: 10dp;

+ 37 - 103
Source/Debugger/ElementInfo.cpp

@@ -300,21 +300,6 @@ void ElementInfo::UpdateSourceElement()
 					if (!value.empty())
 						attributes += Core::CreateString(name.size() + value.size() + 32, "%s: <em>%s</em><br />", name.c_str(), value.c_str());
 				}
-				{
-					name = "style";
-					value = "";
-					const Core::PropertyMap& style_properties = source_element->GetLocalStyleProperties();
-
-					for (auto nvp : style_properties)
-					{
-						auto& prop_name = Core::StyleSheetSpecification::GetPropertyName(nvp.first);
-						auto prop_value = nvp.second.ToString();
-						value += Core::CreateString(prop_name.size() + prop_value.size() + 12, "%s: %s; ", prop_name.c_str(), prop_value.c_str());
-					}
-
-					if (!value.empty())
-						attributes += Core::CreateString(name.size() + value.size() + 32, "%s: <em>%s</em><br />", name.c_str(), value.c_str());
-				}
 			}
 
 			for(const auto& pair : source_element->GetAttributes())
@@ -419,14 +404,7 @@ void ElementInfo::UpdateSourceElement()
 		int ancestor_depth = 1;
 		while (element_ancestor)
 		{
-			Core::String ancestor_name = element_ancestor->GetTagName();
-			const Core::String ancestor_id = element_ancestor->GetId();
-			if (!ancestor_id.empty())
-			{
-				ancestor_name += "#";
-				ancestor_name += ancestor_id;
-			}
-
+			Core::String ancestor_name = element_ancestor->GetAddress(false, false);
 			ancestors += Core::CreateString(ancestor_name.size() + 32, "<p id=\"a %d\">%s</p>", ancestor_depth, ancestor_name.c_str());
 			element_ancestor = element_ancestor->GetParentNode();
 			ancestor_depth++;
@@ -486,78 +464,63 @@ void ElementInfo::UpdateSourceElement()
 
 void ElementInfo::BuildElementPropertiesRML(Core::String& property_rml, Core::Element* element, Core::Element* primary_element)
 {
-	NamedPropertyMap property_map;
+	NamedPropertyList property_list;
 
 	for(auto it = element->IterateLocalProperties(); !it.AtEnd(); ++it)
 	{
-		const Core::PropertyId property_id = it.GetId();
+		Core::PropertyId property_id = it.GetId();
 		const Core::String& property_name = it.GetName();
-		const Core::Property* property = &it.GetProperty();
-		const Core::PseudoClassList& property_pseudo_classes = it.GetPseudoClassList();
+		const Core::Property* prop = &it.GetProperty();
 
 		// Check that this property isn't overridden or just not inherited.
-		if (primary_element->GetProperty(property_id) != property)
+		if (primary_element->GetLocalProperty(property_id) != prop)
 			continue;
 
-		NamedPropertyMap::iterator i = std::find_if(property_map.begin(), property_map.end(),
-			[&property_pseudo_classes](const NamedPropertyPair& pair) { return pair.first == property_pseudo_classes; }
-		);
-		if (i == property_map.end())
-		{
-			property_map.emplace_back(property_pseudo_classes, NamedPropertyList(1, NamedProperty(property_name, property)));
-		}
-		else
-		{
-			// Find a place in this list of properties to insert the new one.
-			NamedPropertyList& properties = (*i).second;
-			NamedPropertyList::iterator insert_iterator = properties.begin();
-			while (insert_iterator != properties.end())
-			{
-				int source_cmp = strcasecmp((*insert_iterator).second->source.c_str(), property->source.c_str());
-				if (source_cmp > 0 ||
-					(source_cmp == 0 && (*insert_iterator).second->source_line_number >= property->source_line_number))
-					break;
-
-				++insert_iterator;
-			}
+		property_list.push_back(NamedProperty{ property_name, prop });
+	}
 
-			(*i).second.insert(insert_iterator, NamedProperty(property_name, property));
+	std::sort(property_list.begin(), property_list.end(),
+		[](const NamedProperty& a, const NamedProperty& b) {
+			if (a.second->source && !b.second->source) return false;
+			if (!a.second->source && b.second->source) return true;
+			return a.second->specificity > b.second->specificity; 
 		}
-	}
+	);
 
-	if (!property_map.empty())
+	if (!property_list.empty())
 	{
 		// Print the 'inherited from ...' header if we're not the primary element.
 		if (element != primary_element)
-			property_rml += Core::CreateString(element->GetTagName().size() + 32, "<h3>inherited from %s</h3>", element->GetTagName().c_str());
-
-		for (const NamedPropertyPair& pair : property_map)
 		{
-			if (pair.first.empty())
-			{
-				BuildPropertiesRML(property_rml, pair.second);
-				break;
-			}
+			property_rml += "<h3 class='mark'>inherited from " + element->GetAddress(false, false) + "</h3>";
 		}
 
-		for (NamedPropertyMap::iterator i = property_map.begin(); i != property_map.end(); ++i)
-		{
-			// Skip the base property list, we've already printed it.
-			if (i->first.empty())
-				continue;
-
-			// Print the pseudo-class header.
-			property_rml += "<h3>";
+		const Core::PropertySource* previous_source = nullptr;
+		bool first_iteration = true;
 
-			for (Core::PseudoClassList::const_iterator j = (*i).first.begin(); j != (*i).first.end(); ++j)
+		for (auto& named_property : property_list)
+		{
+			auto& source = named_property.second->source;
+			if(source.get() != previous_source || first_iteration)
 			{
-				property_rml += " :";
-				property_rml += *j;
-			}
+				previous_source = source.get();
+				first_iteration = false;
 
-			property_rml += "</h3>";
+				// Print the rule name header.
+				if(source)
+				{
+					Core::String str_line_number;
+					Core::TypeConverter<int, Core::String>::Convert(source->line_number, str_line_number);
+					property_rml += "<h3>" + source->rule_name + "</h3>";
+					property_rml += "<h4>" + source->path + " : " + str_line_number + "</h4>";
+				}
+				else
+				{
+					property_rml += "<h3><em>inline</em></h3>";
+				}
+			}
 
-			BuildPropertiesRML(property_rml, (*i).second);
+			BuildPropertyRML(property_rml, named_property.first, named_property.second);
 		}
 	}
 
@@ -565,35 +528,6 @@ void ElementInfo::BuildElementPropertiesRML(Core::String& property_rml, Core::El
 		BuildElementPropertiesRML(property_rml, element->GetParentNode(), primary_element);
 }
 
-void ElementInfo::BuildPropertiesRML(Core::String& property_rml, const NamedPropertyList& properties)
-{
-	Core::String last_source;
-	int last_source_line = -1;
-
-	for (size_t i = 0; i < properties.size(); ++i)
-	{
-		if (i == 0 ||
-			last_source != properties[i].second->source ||
-			last_source_line != properties[i].second->source_line_number)
-		{
-			last_source = properties[i].second->source;
-			last_source_line = properties[i].second->source_line_number;
-
-			property_rml += "<h4>";
-
-			if (last_source.empty() &&
-				last_source_line == 0)
-				property_rml += "<em>inline</em>";
-			else
-				property_rml += Core::CreateString(last_source.size() + 32, "<em>%s</em>: %d", last_source.c_str(), last_source_line);
-
-			property_rml += "</h4>";
-		}
-
-		BuildPropertyRML(property_rml, properties[i].first, properties[i].second);
-	}
-}
-
 void ElementInfo::BuildPropertyRML(Core::String& property_rml, const Core::String& name, const Core::Property* property)
 {
 	Core::String property_value = property->ToString();

+ 0 - 3
Source/Debugger/ElementInfo.h

@@ -37,8 +37,6 @@ namespace Debugger {
 
 typedef std::pair< Core::String, const Core::Property* > NamedProperty;
 typedef std::vector< NamedProperty > NamedPropertyList;
-typedef std::pair<Core::PseudoClassList, NamedPropertyList> NamedPropertyPair;
-typedef std::vector< NamedPropertyPair > NamedPropertyMap;
 
 /**
 	@author Robert Curry
@@ -72,7 +70,6 @@ private:
 	void UpdateSourceElement();
 
 	void BuildElementPropertiesRML(Core::String& property_rml, Core::Element* element, Core::Element* primary_element);
-	void BuildPropertiesRML(Core::String& property_rml, const NamedPropertyList& properties);
 	void BuildPropertyRML(Core::String& property_rml, const Core::String& name, const Core::Property* property);
 
 	void RemoveTrailingZeroes(Core::String& string);