Browse Source

Merge pull request #81 from viciious/optimizations_get_property

Optimize document re-layout by caching layout-important CSS properties
Lloyd Weehuizen 13 years ago
parent
commit
eec22fc152
32 changed files with 952 additions and 123 deletions
  1. 6 0
      Build/Rocket.xcodeproj/project.pbxproj
  2. 8 0
      Build/RocketCore.vcproj
  3. 2 0
      Build/cmake/FileList.cmake
  4. 8 0
      Build/vc2010/RocketCore.vcproj
  5. 2 0
      Build/vc2010/RocketCore.vcxproj
  6. 2 0
      Build/vc2012/RocketCore.vcxproj
  7. 40 0
      Include/Rocket/Core/Element.h
  8. 107 7
      Source/Core/Element.cpp
  9. 7 4
      Source/Core/ElementHandle.cpp
  10. 163 32
      Source/Core/ElementStyle.cpp
  11. 49 2
      Source/Core/ElementStyle.h
  12. 341 0
      Source/Core/ElementStyleCache.cpp
  13. 130 0
      Source/Core/ElementStyleCache.h
  14. 4 4
      Source/Core/ElementTextDefault.cpp
  15. 10 22
      Source/Core/ElementUtilities.cpp
  16. 4 5
      Source/Core/LayoutBlockBox.cpp
  17. 1 1
      Source/Core/LayoutBlockBoxSpace.cpp
  18. 48 29
      Source/Core/LayoutEngine.cpp
  19. 2 2
      Source/Core/LayoutInlineBox.cpp
  20. 1 1
      Source/Core/LayoutLineBox.cpp
  21. 1 1
      Source/Core/StyleSheetNodeSelectorEmpty.cpp
  22. 1 1
      Source/Core/StyleSheetNodeSelectorFirstChild.cpp
  23. 1 1
      Source/Core/StyleSheetNodeSelectorFirstOfType.cpp
  24. 1 1
      Source/Core/StyleSheetNodeSelectorLastChild.cpp
  25. 1 1
      Source/Core/StyleSheetNodeSelectorLastOfType.cpp
  26. 1 1
      Source/Core/StyleSheetNodeSelectorNthChild.cpp
  27. 1 1
      Source/Core/StyleSheetNodeSelectorNthLastChild.cpp
  28. 1 1
      Source/Core/StyleSheetNodeSelectorNthLastOfType.cpp
  29. 1 1
      Source/Core/StyleSheetNodeSelectorNthOfType.cpp
  30. 1 1
      Source/Core/StyleSheetNodeSelectorOnlyChild.cpp
  31. 1 1
      Source/Core/StyleSheetNodeSelectorOnlyOfType.cpp
  32. 6 3
      Source/Core/WidgetSlider.cpp

+ 6 - 0
Build/Rocket.xcodeproj/project.pbxproj

@@ -82,6 +82,7 @@
 		6E8B1E04123ABCC200C451C8 /* ElementReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3712058A45000FAF17 /* ElementReference.cpp */; };
 		6E8B1E05123ABCC200C451C8 /* ElementScroll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3812058A45000FAF17 /* ElementScroll.cpp */; };
 		6E8B1E06123ABCC200C451C8 /* ElementStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3912058A45000FAF17 /* ElementStyle.cpp */; };
+		6E8B1E06123ABCC200C451C8 /* ElementStyleCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3912058A45000FAF17 /* ElementStyleCache.cpp */; };
 		6E8B1E07123ABCC200C451C8 /* ElementText.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3B12058A45000FAF17 /* ElementText.cpp */; };
 		6E8B1E08123ABCC200C451C8 /* ElementTextDefault.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3C12058A45000FAF17 /* ElementTextDefault.cpp */; };
 		6E8B1E09123ABCC200C451C8 /* ElementUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3E12058A45000FAF17 /* ElementUtilities.cpp */; };
@@ -271,6 +272,7 @@
 		6EF28E6312058A45000FAF17 /* ElementReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3712058A45000FAF17 /* ElementReference.cpp */; };
 		6EF28E6412058A45000FAF17 /* ElementScroll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3812058A45000FAF17 /* ElementScroll.cpp */; };
 		6EF28E6512058A45000FAF17 /* ElementStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3912058A45000FAF17 /* ElementStyle.cpp */; };
+		6EF28E6512058A45000FAF17 /* ElementStyleCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3912058A45000FAF17 /* ElementStyleCache.cpp */; };
 		6EF28E6712058A45000FAF17 /* ElementText.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3B12058A45000FAF17 /* ElementText.cpp */; };
 		6EF28E6812058A45000FAF17 /* ElementTextDefault.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3C12058A45000FAF17 /* ElementTextDefault.cpp */; };
 		6EF28E6A12058A45000FAF17 /* ElementUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EF28D3E12058A45000FAF17 /* ElementUtilities.cpp */; };
@@ -626,6 +628,7 @@
 		6EF28D3712058A45000FAF17 /* ElementReference.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ElementReference.cpp; path = ../Source/Core/ElementReference.cpp; sourceTree = SOURCE_ROOT; };
 		6EF28D3812058A45000FAF17 /* ElementScroll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ElementScroll.cpp; path = ../Source/Core/ElementScroll.cpp; sourceTree = SOURCE_ROOT; };
 		6EF28D3912058A45000FAF17 /* ElementStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ElementStyle.cpp; path = ../Source/Core/ElementStyle.cpp; sourceTree = SOURCE_ROOT; };
+		6EF28D3912058A45000FAF17 /* ElementStyleCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ElementStyleCache.cpp; path = ../Source/Core/ElementStyleCache.cpp; sourceTree = SOURCE_ROOT; };
 		6EF28D3B12058A45000FAF17 /* ElementText.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ElementText.cpp; path = ../Source/Core/ElementText.cpp; sourceTree = SOURCE_ROOT; };
 		6EF28D3C12058A45000FAF17 /* ElementTextDefault.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ElementTextDefault.cpp; path = ../Source/Core/ElementTextDefault.cpp; sourceTree = SOURCE_ROOT; };
 		6EF28D3E12058A45000FAF17 /* ElementUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ElementUtilities.cpp; path = ../Source/Core/ElementUtilities.cpp; sourceTree = SOURCE_ROOT; };
@@ -985,6 +988,7 @@
 				6EF28D3712058A45000FAF17 /* ElementReference.cpp */,
 				6EF28D3812058A45000FAF17 /* ElementScroll.cpp */,
 				6EF28D3912058A45000FAF17 /* ElementStyle.cpp */,
+				6EF28D3912058A45000FAF17 /* ElementStyleCache.cpp */,
 				6EF28D3B12058A45000FAF17 /* ElementText.cpp */,
 				6EF28D3C12058A45000FAF17 /* ElementTextDefault.cpp */,
 				6EF28D3E12058A45000FAF17 /* ElementUtilities.cpp */,
@@ -1608,6 +1612,7 @@
 				6E8B1E04123ABCC200C451C8 /* ElementReference.cpp in Sources */,
 				6E8B1E05123ABCC200C451C8 /* ElementScroll.cpp in Sources */,
 				6E8B1E06123ABCC200C451C8 /* ElementStyle.cpp in Sources */,
+				6E8B1E06123ABCC200C451C8 /* ElementStyleCache.cpp in Sources */,
 				6E8B1E07123ABCC200C451C8 /* ElementText.cpp in Sources */,
 				6E8B1E08123ABCC200C451C8 /* ElementTextDefault.cpp in Sources */,
 				6E8B1E09123ABCC200C451C8 /* ElementUtilities.cpp in Sources */,
@@ -1813,6 +1818,7 @@
 				6EF28E6312058A45000FAF17 /* ElementReference.cpp in Sources */,
 				6EF28E6412058A45000FAF17 /* ElementScroll.cpp in Sources */,
 				6EF28E6512058A45000FAF17 /* ElementStyle.cpp in Sources */,
+				6EF28E6512058A45000FAF17 /* ElementStyleCache.cpp in Sources */,
 				6EF28E6712058A45000FAF17 /* ElementText.cpp in Sources */,
 				6EF28E6812058A45000FAF17 /* ElementTextDefault.cpp in Sources */,
 				6EF28E6A12058A45000FAF17 /* ElementUtilities.cpp in Sources */,

+ 8 - 0
Build/RocketCore.vcproj

@@ -287,6 +287,14 @@
 				RelativePath="..\Source\Core\ElementStyle.h"
 				>
 			</File>
+			<File
+				RelativePath="..\Source\Core\ElementStyleCache.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\Source\Core\ElementStyleCache.h"
+				>
+			</File>			
 			<File
 				RelativePath="..\Source\Core\ElementUtilities.cpp"
 				>

+ 2 - 0
Build/cmake/FileList.cmake

@@ -4,6 +4,7 @@ set(Core_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstOfType.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBoxInstancer.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyle.h
+	${PROJECT_SOURCE_DIR}/Source/Core/ElementStyleCache.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancerDefault.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementDefinition.h
@@ -219,6 +220,7 @@ set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSlider.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Property.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyle.cpp
+	${PROJECT_SOURCE_DIR}/Source/Core/ElementStyleCache.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNoneInstancer.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Element.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutlineInstancer.cpp

+ 8 - 0
Build/vc2010/RocketCore.vcproj

@@ -287,6 +287,14 @@
 				RelativePath="..\..\Source\Core\ElementStyle.h"
 				>
 			</File>
+			<File
+				RelativePath="..\..\Source\Core\ElementStyleCache.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\Source\Core\ElementStyleCache.h"
+				>
+			</File>
 			<File
 				RelativePath="..\..\Source\Core\ElementUtilities.cpp"
 				>

+ 2 - 0
Build/vc2010/RocketCore.vcxproj

@@ -90,6 +90,7 @@
     <ClCompile Include="..\..\Source\Core\ElementReference.cpp" />
     <ClCompile Include="..\..\Source\Core\ElementScroll.cpp" />
     <ClCompile Include="..\..\Source\Core\ElementStyle.cpp" />
+	<ClCompile Include="..\..\Source\Core\ElementStyleCache.cpp" />
     <ClCompile Include="..\..\Source\Core\ElementUtilities.cpp" />
     <ClCompile Include="..\..\Source\Core\LayoutBlockBox.cpp" />
     <ClCompile Include="..\..\Source\Core\LayoutBlockBoxSpace.cpp" />
@@ -225,6 +226,7 @@
     <ClInclude Include="..\..\Include\Rocket\Core\ElementReference.h" />
     <ClInclude Include="..\..\Include\Rocket\Core\ElementScroll.h" />
     <ClInclude Include="..\..\Source\Core\ElementStyle.h" />
+	<ClInclude Include="..\..\Source\Core\ElementStyleCache.h" />
     <ClInclude Include="..\..\Include\Rocket\Core\ElementUtilities.h" />
     <ClInclude Include="..\..\Source\Core\LayoutBlockBox.h" />
     <ClInclude Include="..\..\Source\Core\LayoutBlockBoxSpace.h" />

+ 2 - 0
Build/vc2012/RocketCore.vcxproj

@@ -92,6 +92,7 @@
     <ClCompile Include="..\..\Source\Core\ElementReference.cpp" />
     <ClCompile Include="..\..\Source\Core\ElementScroll.cpp" />
     <ClCompile Include="..\..\Source\Core\ElementStyle.cpp" />
+	<ClCompile Include="..\..\Source\Core\ElementStyleCache.cpp" />
     <ClCompile Include="..\..\Source\Core\ElementUtilities.cpp" />
     <ClCompile Include="..\..\Source\Core\LayoutBlockBox.cpp" />
     <ClCompile Include="..\..\Source\Core\LayoutBlockBoxSpace.cpp" />
@@ -227,6 +228,7 @@
     <ClInclude Include="..\..\Include\Rocket\Core\ElementReference.h" />
     <ClInclude Include="..\..\Include\Rocket\Core\ElementScroll.h" />
     <ClInclude Include="..\..\Source\Core\ElementStyle.h" />
+	<ClInclude Include="..\..\Source\Core\ElementStyleCache.h" />
     <ClInclude Include="..\..\Include\Rocket\Core\ElementUtilities.h" />
     <ClInclude Include="..\..\Source\Core\LayoutBlockBox.h" />
     <ClInclude Include="..\..\Source\Core\LayoutBlockBoxSpace.h" />

+ 40 - 0
Include/Rocket/Core/Element.h

@@ -220,6 +220,43 @@ public:
 	/// @param[in] base_value The value that is scaled by the percentage value, if it is a percentage.
 	/// @return The value of this property for this element.
 	float ResolveProperty(const String& name, float base_value);
+	/// Resolves one of this element's non-inherited properties. If the value is a number or px, this is returned. If it's a 
+	/// percentage then it is resolved based on the second argument (the base value).
+	/// @param[in] name The property to resolve the value for.
+	/// @param[in] base_value The value that is scaled by the percentage value, if it is a percentage.
+	/// @return The value of this property for this element.
+	float ResolveProperty(const Property *property, float base_value);
+
+	/// Returns 'border-width' properties from element's style or local cache.
+	void GetBorderWidthProperties(const Property **border_top_width, const Property **border_bottom_width, const Property **border_left_width, const Property **border_right_width);
+	/// Returns 'margin' properties from element's style or local cache.
+	void GetMarginProperties(const Property **margin_top, const Property **margin_bottom, const Property **margin_left, const Property **margin_right);
+	/// Returns 'padding' properties from element's style or local cache.
+	void GetPaddingProperties(const Property **padding_top, const Property **padding_bottom, const Property **padding_left, const Property **padding_right);
+	/// Returns 'width' and 'height' properties from element's style or local cache.
+	void GetDimensionProperties(const Property **width, const Property **height);
+	/// Returns local 'width' and 'height' properties from element's style or local cache,
+	/// ignoring default values.
+	void GetLocalDimensionProperties(const Property **width, const Property **height);
+	/// Returns 'overflow' properties' values from element's style or local cache.
+	void GetOverflow(int *overflow_x, int *overflow_y);
+	/// Returns 'position' property value from element's style or local cache.
+	int GetPosition();
+	/// Returns 'float' property value from element's style or local cache.
+	int GetFloat();
+	/// Returns 'display' property value from element's style or local cache.
+	int GetDisplay();
+	/// Returns 'white-space' property value from element's style or local cache.
+	int GetWhitespace();
+
+	/// Returns 'line-height' property value from element's style or local cache.
+	const Property *GetLineHeightProperty();
+	/// Returns 'text-align' property value from element's style or local cache.
+	int GetTextAlign();
+	/// Returns 'text-transform' property value from element's style or local cache.
+	int GetTextTransform();
+	/// Returns 'vertical-align' property value from element's style or local cache.
+	const Property *GetVerticalAlignProperty();
 
 	/// Iterates over the properties defined on this element.
 	/// @param[inout] index Index of the property to fetch. This is incremented to the next valid index after the fetch. Indices are not necessarily incremental.
@@ -574,6 +611,9 @@ protected:
 	/// Returns true if the element has been marked as needing a re-layout.
 	virtual bool IsLayoutDirty();
 
+	/// Increment/Decrement the layout lock
+	virtual void LockLayout(bool lock);
+
 	/// Forces a reevaluation of applicable font effects.
 	virtual void DirtyFont();
 

+ 107 - 7
Source/Core/Element.cpp

@@ -293,7 +293,7 @@ String Element::GetAddress(bool include_pseudo_classes) const
 // Sets the position of this element, as a two-dimensional offset from another element.
 void Element::SetOffset(const Vector2f& offset, Element* _offset_parent, bool _offset_fixed)
 {
-	_offset_fixed |= GetProperty< int >(POSITION) == POSITION_FIXED;
+	_offset_fixed |= GetPosition() == POSITION_FIXED;
 
 	// If our offset has definitely changed, or any of our parenting has, then these are set and
 	// updated based on our left / right / top / bottom properties.
@@ -529,6 +529,82 @@ float Element::ResolveProperty(const String& name, float base_value)
 	return style->ResolveProperty(name, base_value);
 }
 
+// Resolves one of this element's style.
+float Element::ResolveProperty(const Property *property, float base_value)
+{
+	return style->ResolveProperty(property, base_value);
+}
+
+void Element::GetBorderWidthProperties(const Property **border_top, const Property **border_bottom, const Property **border_left, const Property **bottom_right)
+{
+	style->GetBorderWidthProperties(border_top, border_bottom, border_left, bottom_right);
+}
+
+void Element::GetMarginProperties(const Property **margin_top, const Property **margin_bottom, const Property **margin_left, const Property **margin_right)
+{
+	style->GetMarginProperties(margin_top, margin_bottom, margin_left, margin_right);
+}
+
+void Element::GetPaddingProperties(const Property **padding_top, const Property **padding_bottom, const Property **padding_left, const Property **padding_right)
+{
+	style->GetPaddingProperties(padding_top, padding_bottom, padding_left, padding_right);
+}
+
+void Element::GetDimensionProperties(const Property **width, const Property **height)
+{
+	style->GetDimensionProperties(width, height);
+}
+
+void Element::GetLocalDimensionProperties(const Property **width, const Property **height)
+{
+	style->GetLocalDimensionProperties(width, height);
+}
+
+void Element::GetOverflow(int *overflow_x, int *overflow_y)
+{
+	style->GetOverflow(overflow_x, overflow_y);
+}
+
+int Element::GetPosition()
+{
+	return style->GetPosition();
+}
+
+int Element::GetFloat()
+{
+	return style->GetFloat();
+}
+
+int Element::GetDisplay()
+{
+	return style->GetDisplay();
+}
+
+int Element::GetWhitespace()
+{
+	return style->GetWhitespace();
+}
+
+const Property *Element::GetLineHeightProperty()
+{
+	return style->GetLineHeightProperty();
+}
+
+int Element::GetTextAlign()
+{
+	return style->GetTextAlign();
+}
+
+int Element::GetTextTransform()
+{
+	return style->GetTextTransform();
+}
+
+const Property *Element::GetVerticalAlignProperty()
+{
+	return style->GetVerticalAlignProperty();
+}
+
 // Iterates over the properties defined on this element.
 bool Element::IterateProperties(int& index, PseudoClassList& pseudo_classes, String& name, const Property*& property) const
 {
@@ -1019,6 +1095,8 @@ void Element::ScrollIntoView(bool align_with_top)
 // Appends a child to this element
 void Element::AppendChild(Element* child, bool dom_element)
 {
+	LockLayout(true);
+
 	child->AddReference();
 	child->SetParent(this);
 	if (dom_element)
@@ -1038,6 +1116,8 @@ void Element::AppendChild(Element* child, bool dom_element)
 
 	if (dom_element)
 		DirtyLayout();
+
+	LockLayout(false);
 }
 
 // Adds a child to this element, directly after the adjacent element. Inherits
@@ -1063,6 +1143,8 @@ void Element::InsertBefore(Element* child, Element* adjacent_element)
 
 	if (found_child)
 	{
+		LockLayout(true);
+
 		child->AddReference();
 		child->SetParent(this);
 
@@ -1079,6 +1161,8 @@ void Element::InsertBefore(Element* child, Element* adjacent_element)
 		child->OnChildAdd(child);
 		DirtyStackingContext();
 		DirtyStructure();
+
+		LockLayout(false);
 	}
 	else
 	{
@@ -1104,6 +1188,8 @@ bool Element::ReplaceChild(Element* inserted_element, Element* replaced_element)
 		return false;
 	}
 
+	LockLayout(true);
+
 	children.insert(insertion_point, inserted_element);
 	RemoveChild(replaced_element);
 
@@ -1111,6 +1197,8 @@ bool Element::ReplaceChild(Element* inserted_element, Element* replaced_element)
 	inserted_element->GetStyle()->DirtyProperties();
 	inserted_element->OnChildAdd(inserted_element);
 
+	LockLayout(false);
+
 	return true;
 }
 
@@ -1124,6 +1212,8 @@ bool Element::RemoveChild(Element* child)
 		// Add the element to the delete list
 		if ((*itr) == child)
 		{
+			LockLayout(true);
+
 			// Inform the context of the element's pending removal (if we have a valid context).
 			Context* context = GetContext();
 			if (context)
@@ -1165,6 +1255,8 @@ bool Element::RemoveChild(Element* child)
 			DirtyStackingContext();
 			DirtyStructure();
 
+			LockLayout(false);
+
 			return true;
 		}
 
@@ -1378,8 +1470,8 @@ void Element::OnPropertyChange(const PropertyNameList& changed_properties)
 	if (all_dirty || changed_properties.find(VISIBILITY) != changed_properties.end() ||
 		changed_properties.find(DISPLAY) != changed_properties.end())
 	{
-		bool new_visibility = GetProperty< int >(VISIBILITY) == VISIBILITY_VISIBLE &&
-							  GetProperty< int >(DISPLAY) != DISPLAY_NONE;
+		bool new_visibility = GetDisplay() != DISPLAY_NONE &&
+							  GetProperty< int >(VISIBILITY) == VISIBILITY_VISIBLE;
 
 		if (visible != new_visibility)
 		{
@@ -1560,6 +1652,14 @@ void Element::DirtyLayout()
 		document->DirtyLayout();
 }
 
+/// Increment/Decrement the layout lock
+void Element::LockLayout(bool lock)
+{
+	Element* document = GetOwnerDocument();
+	if (document != NULL)
+		document->LockLayout(lock);
+}
+
 // Forces a re-layout of this element, and any other children required.
 bool Element::IsLayoutDirty()
 {
@@ -1717,7 +1817,7 @@ void Element::DirtyOffset()
 
 void Element::UpdateOffset()
 {
-	int position_property = GetProperty< int >(POSITION);
+	int position_property = GetPosition();
 	if (position_property == POSITION_ABSOLUTE ||
 		position_property == POSITION_FIXED)
 	{
@@ -1810,11 +1910,11 @@ void Element::BuildStackingContext(ElementList* new_stacking_context)
 		std::pair< Element*, float > ordered_child;
 		ordered_child.first = child;
 
-		if (child->GetProperty< int >(POSITION) != POSITION_STATIC)
+		if (child->GetPosition() != POSITION_STATIC)
 			ordered_child.second = 3;
-		else if (child->GetProperty< int >(FLOAT) != FLOAT_NONE)
+		else if (child->GetFloat() != FLOAT_NONE)
 			ordered_child.second = 1;
-		else if (child->GetProperty< int >(DISPLAY) == DISPLAY_BLOCK)
+		else if (child->GetDisplay() == DISPLAY_BLOCK)
 			ordered_child.second = 0;
 		else
 			ordered_child.second = 2;

+ 7 - 4
Source/Core/ElementHandle.cpp

@@ -113,14 +113,17 @@ void ElementHandle::ProcessEvent(Event& event)
 
 			if (size_target)
 			{
+				const Property *margin_top, *margin_bottom, *margin_left, *margin_right;
+				size_target->GetMarginProperties(&margin_top, &margin_bottom, &margin_left, &margin_right);
+
 				// Check if we have auto-margins; if so, they have to be set to the current margins.
-				if (size_target->GetProperty(MARGIN_TOP)->unit == Property::KEYWORD)
+				if (margin_top->unit == Property::KEYWORD)
 					size_target->SetProperty(MARGIN_TOP, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::TOP)), Property::PX));
-				if (size_target->GetProperty(MARGIN_RIGHT)->unit == Property::KEYWORD)
+				if (margin_right->unit == Property::KEYWORD)
 					size_target->SetProperty(MARGIN_RIGHT, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::RIGHT)), Property::PX));
-				if (size_target->GetProperty(MARGIN_BOTTOM)->unit == Property::KEYWORD)
+				if (margin_bottom->unit == Property::KEYWORD)
 					size_target->SetProperty(MARGIN_BOTTOM, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM)), Property::PX));
-				if (size_target->GetProperty(MARGIN_LEFT)->unit == Property::KEYWORD)
+				if (margin_left->unit == Property::KEYWORD)
 					size_target->SetProperty(MARGIN_LEFT, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::LEFT)), Property::PX));
 
 				int new_x = Math::RealToInteger(size_original_size.x + x);

+ 163 - 32
Source/Core/ElementStyle.cpp

@@ -27,6 +27,7 @@
 
 #include "precompiled.h"
 #include "ElementStyle.h"
+#include "ElementStyleCache.h"
 #include <algorithm>
 #include <Rocket/Core/ElementDocument.h>
 #include <Rocket/Core/ElementUtilities.h>
@@ -47,8 +48,10 @@ namespace Core {
 ElementStyle::ElementStyle(Element* _element)
 {
 	local_properties = NULL;
+	em_properties = NULL;
 	definition = NULL;
 	element = _element;
+	cache = new ElementStyleCache(this);
 
 	definition_dirty = true;
 	child_definition_dirty = true;
@@ -58,9 +61,20 @@ ElementStyle::~ElementStyle()
 {
 	if (local_properties != NULL)
 		delete local_properties;
+	if (em_properties != NULL)
+		delete em_properties;
 
 	if (definition != NULL)
 		definition->RemoveReference();
+
+	delete cache;
+}
+
+static PropCounter prop_counter;
+
+PropCounter &ElementStyle::GetPropCounter()
+{
+	return prop_counter;
 }
 
 // Returns the element's definition, updating if necessary.
@@ -278,6 +292,10 @@ void ElementStyle::RemoveProperty(const String& name)
 // Returns one of this element's properties.
 const Property* ElementStyle::GetProperty(const String& name)
 {
+	if (prop_counter.find(name) == prop_counter.end())
+		prop_counter[name] = 0;
+	prop_counter[name] = prop_counter[name] + 1;
+
 	const Property* local_property = GetLocalProperty(name);
 	if (local_property != NULL)
 		return local_property;
@@ -323,6 +341,32 @@ const Property* ElementStyle::GetLocalProperty(const String& name)
 	return NULL;
 }
 
+// Resolves one of this element's properties.
+float ElementStyle::ResolveProperty(const Property* property, float base_value)
+{
+	if (!property)
+	{
+		ROCKET_ERROR;
+		return 0.0f;
+	}
+
+	if (property->unit & Property::RELATIVE_UNIT)
+	{
+		if (property->unit & Property::PERCENT)
+			return base_value * property->value.Get< float >() * 0.01f;
+		else if (property->unit & Property::EM)
+			return property->value.Get< float >() * ElementUtilities::GetFontSize(element);
+	}
+
+	if (property->unit & Property::NUMBER || property->unit & Property::PX)
+	{
+		return property->value.Get< float >();
+	}
+
+	// We're not a numeric property; return 0.
+	return 0.0f;
+}
+
 // Resolves one of this element's properties.
 float ElementStyle::ResolveProperty(const String& name, float base_value)
 {
@@ -368,23 +412,6 @@ float ElementStyle::ResolveProperty(const String& name, float base_value)
 		return property->value.Get< float >();
 	}
 
-	// Values based on pixels-per-inch.
-	if (property->unit & Property::PPI_UNIT)
-	{
-		float inch = property->value.Get< float >() * element->GetRenderInterface()->GetPixelsPerInch();
-
-		if (property->unit & Property::IN) // inch
-			return inch;
-		if (property->unit & Property::CM) // centimeter
-			return inch / 2.54f;
-		if (property->unit & Property::MM) // millimeter
-			return inch / 25.4f;
-		if (property->unit & Property::PT) // point
-			return inch / 72.0f;
-		if (property->unit & Property::PC) // pica
-			return inch / 6.0f;
-	}
-
 	// We're not a numeric property; return 0.
 	return 0.0f;
 }
@@ -478,22 +505,25 @@ void ElementStyle::DirtyEmProperties()
 {
 	const PropertyNameList &properties = StyleSheetSpecification::GetRegisteredProperties();
 
-	// Check if any of these are currently em-relative. If so, dirty them.
-	PropertyNameList em_properties;
-	for (PropertyNameList::const_iterator list_iterator = properties.begin(); list_iterator != properties.end(); ++list_iterator)
+	if (!em_properties)
 	{
-		// Skip font-size; this is relative to our parent's em, not ours.
-		if (*list_iterator == FONT_SIZE)
-			continue;
-
-		// Get this property from this element. If this is em-relative, then add it to the list to
-		// dirty.
-		if (element->GetProperty(*list_iterator)->unit == Property::EM)
-			em_properties.insert(*list_iterator);
+		// Check if any of these are currently em-relative. If so, dirty them.
+		em_properties = new PropertyNameList;
+		for (PropertyNameList::const_iterator list_iterator = properties.begin(); list_iterator != properties.end(); ++list_iterator)
+		{
+			// Skip font-size; this is relative to our parent's em, not ours.
+			if (*list_iterator == FONT_SIZE)
+				continue;
+
+			// Get this property from this element. If this is em-relative, then add it to the list to
+			// dirty.
+			if (element->GetProperty(*list_iterator)->unit == Property::EM)
+				em_properties->insert(*list_iterator);
+		}
 	}
 
-	if (!em_properties.empty())
-		DirtyProperties(em_properties);
+	if (!em_properties->empty())
+		DirtyProperties(*em_properties, false);
 
 	// Now dirty all of our descendant's font-size properties that are relative to ems.
 	int num_children = element->GetNumChildren(true);
@@ -528,7 +558,7 @@ void ElementStyle::DirtyProperty(const String& property)
 }
 
 // Sets a list of properties as dirty.
-void ElementStyle::DirtyProperties(const PropertyNameList& properties)
+void ElementStyle::DirtyProperties(const PropertyNameList& properties, bool clear_em_properties)
 {
 	if (properties.empty())
 		return;
@@ -542,6 +572,9 @@ void ElementStyle::DirtyProperties(const PropertyNameList& properties)
 		const PropertyNameList &all_inherited_properties = StyleSheetSpecification::GetRegisteredInheritedProperties();
 		for (int i = 0; i < element->GetNumChildren(true); i++)
 			element->GetChild(i)->GetStyle()->DirtyInheritedProperties(all_inherited_properties);
+
+		// Clear all cached properties.
+		cache->Clear();
 	}
 	else
 	{
@@ -562,6 +595,16 @@ void ElementStyle::DirtyProperties(const PropertyNameList& properties)
 			for (int i = 0; i < element->GetNumChildren(true); i++)
 				element->GetChild(i)->GetStyle()->DirtyInheritedProperties(inherited_properties);
 		}
+
+		// Clear cached properties.
+		cache->Clear();
+	}
+
+	// clear the list of EM-properties, we will refill it in DirtyEmProperties
+	if (clear_em_properties && em_properties != NULL)
+	{
+		delete em_properties;
+		em_properties = NULL;
 	}
 
 	// And send the event.
@@ -571,16 +614,34 @@ void ElementStyle::DirtyProperties(const PropertyNameList& properties)
 // Sets a list of our potentially inherited properties as dirtied by an ancestor.
 void ElementStyle::DirtyInheritedProperties(const PropertyNameList& properties)
 {
+	bool clear_em_properties = em_properties != NULL;
+
 	PropertyNameList inherited_properties;
 	for (PropertyNameList::const_iterator i = properties.begin(); i != properties.end(); ++i)
 	{
-		if (GetLocalProperty((*i)) == NULL)
+		const Property *property = GetLocalProperty((*i));
+		if (property == NULL)
+		{
 			inherited_properties.insert(*i);
+			if (!clear_em_properties && em_properties != NULL && em_properties->find((*i)) != em_properties->end()) {
+				clear_em_properties = true;
+			}
+		}
 	}
 
 	if (inherited_properties.empty())
 		return;
 
+	// clear the list of EM-properties, we will refill it in DirtyEmProperties
+	if (clear_em_properties && em_properties != NULL)
+	{
+		delete em_properties;
+		em_properties = NULL;
+	}
+
+	// Clear cached inherited properties.
+	cache->ClearInherited();
+
 	// Pass the list of those properties that this element doesn't override onto our children.
 	for (int i = 0; i < element->GetNumChildren(true); i++)
 		element->GetChild(i)->GetStyle()->DirtyInheritedProperties(inherited_properties);
@@ -588,5 +649,75 @@ void ElementStyle::DirtyInheritedProperties(const PropertyNameList& properties)
 	element->OnPropertyChange(properties);
 }
 
+void ElementStyle::GetBorderWidthProperties(const Property **border_top_width, const Property **border_bottom_width, const Property **border_left_width, const Property **bottom_right_width)
+{
+	cache->GetBorderWidthProperties(border_top_width, border_bottom_width, border_left_width, bottom_right_width);
+}
+
+void ElementStyle::GetMarginProperties(const Property **margin_top, const Property **margin_bottom, const Property **margin_left, const Property **margin_right)
+{
+	cache->GetMarginProperties(margin_top, margin_bottom, margin_left, margin_right);
+}
+
+void ElementStyle::GetPaddingProperties(const Property **padding_top, const Property **padding_bottom, const Property **padding_left, const Property **padding_right)
+{
+	cache->GetPaddingProperties(padding_top, padding_bottom, padding_left, padding_right);
+}
+
+void ElementStyle::GetDimensionProperties(const Property **width, const Property **height)
+{
+	cache->GetDimensionProperties(width, height);
+}
+
+void ElementStyle::GetLocalDimensionProperties(const Property **width, const Property **height)
+{
+	cache->GetLocalDimensionProperties(width, height);
+}
+
+void ElementStyle::GetOverflow(int *overflow_x, int *overflow_y)
+{
+	cache->GetOverflow(overflow_x, overflow_y);
+}
+
+int ElementStyle::GetPosition()
+{
+	return cache->GetPosition();
+}
+
+int ElementStyle::GetFloat()
+{
+	return cache->GetFloat();
+}
+
+int ElementStyle::GetDisplay()
+{
+	return cache->GetDisplay();
+}
+
+int ElementStyle::GetWhitespace()
+{
+	return cache->GetWhitespace();
+}
+
+const Property *ElementStyle::GetLineHeightProperty()
+{
+	return cache->GetLineHeightProperty();
+}
+
+int ElementStyle::GetTextAlign()
+{
+	return cache->GetTextAlign();
+}
+
+int ElementStyle::GetTextTransform()
+{
+	return cache->GetTextTransform();
+}
+
+const Property *ElementStyle::GetVerticalAlignProperty()
+{
+	return cache->GetVerticalAlignProperty();
+}
+
 }
 }

+ 49 - 2
Source/Core/ElementStyle.h

@@ -34,6 +34,10 @@
 namespace Rocket {
 namespace Core {
 
+class ElementStyleCache;
+
+typedef std::map<String, int> PropCounter;
+
 /**
 	Manages an element's style and property information.
 	@author Lloyd Weehuizen
@@ -103,6 +107,12 @@ public:
 	const Property* GetLocalProperty(const String& name);
 	/// Resolves one of this element's properties. If the value is a number or px, this is returned. If it's a 
 	/// percentage then it is resolved based on the second argument (the base value).
+	/// @param[in] property Property to resolve the value for.
+	/// @param[in] base_value The value that is scaled by the percentage value, if it is a percentage.
+	/// @return The value of this property for this element.
+	float ResolveProperty(const Property *property, float base_value);
+	/// Resolves one of this element's properties. If the value is a number or px, this is returned. If it's a 
+	/// percentage then it is resolved based on the second argument (the base value).
 	/// @param[in] name The name of the property to resolve the value for.
 	/// @param[in] base_value The value that is scaled by the percentage value, if it is a percentage.
 	/// @return The value of this property for this element.
@@ -131,11 +141,44 @@ public:
 	// Dirties font-size on child elements if appropriate.
 	void DirtyInheritedEmProperties();
 
+	/// Returns 'border-width' properties from element's style or local cache.
+	void GetBorderWidthProperties(const Property **border_top_width, const Property **border_bottom_width, const Property **border_left_width, const Property **border_right_width);
+	/// Returns 'margin' properties from element's style or local cache.
+	void GetMarginProperties(const Property **margin_top, const Property **margin_bottom, const Property **margin_left, const Property **margin_right);
+	/// Returns 'padding' properties from element's style or local cache.
+	void GetPaddingProperties(const Property **padding_top, const Property **padding_bottom, const Property **padding_left, const Property **padding_right);
+	/// Returns 'width' and 'height' properties from element's style or local cache.
+	void GetDimensionProperties(const Property **width, const Property **height);
+	/// Returns local 'width' and 'height' properties from element's style or local cache,
+	/// ignoring default values.
+	void GetLocalDimensionProperties(const Property **width, const Property **height);
+	/// Returns 'overflow' properties' values from element's style or local cache.
+	void GetOverflow(int *overflow_x, int *overflow_y);
+	/// Returns 'position' property value from element's style or local cache.
+	int GetPosition();
+	/// Returns 'float' property value from element's style or local cache.
+	int GetFloat();
+	/// Returns 'display' property value from element's style or local cache.
+	int GetDisplay();
+	/// Returns 'white-space' property value from element's style or local cache.
+	int GetWhitespace();
+
+	/// Returns 'line-height' property value from element's style or local cache.
+	const Property *GetLineHeightProperty();
+	/// Returns 'text-align' property value from element's style or local cache.
+	int GetTextAlign();
+	/// Returns 'text-transform' property value from element's style or local cache.
+	int GetTextTransform();
+	/// Returns 'vertical-align' property value from element's style or local cache.
+	const Property *GetVerticalAlignProperty();
+
+	static PropCounter &GetPropCounter();
+
 private:
 	// Sets a single property as dirty.
 	void DirtyProperty(const String& property);
 	// Sets a list of properties as dirty.
-	void DirtyProperties(const PropertyNameList& properties);
+	void DirtyProperties(const PropertyNameList& properties, bool clear_em_properties = true);
 	// Sets a list of our potentially inherited properties as dirtied by an ancestor.
 	void DirtyInheritedProperties(const PropertyNameList& properties);
 
@@ -147,14 +190,18 @@ private:
 	// This element's current pseudo-classes.
 	PseudoClassList pseudo_classes;
 
-	// Any properties that have been overridden in this element;
+	// Any properties that have been overridden in this element.
 	PropertyDictionary* local_properties;
+	// All properties (including inherited) that are EM-relative.
+	PropertyNameList* em_properties;
 	// The definition of this element; if this is NULL one will be fetched from the element's style.
 	ElementDefinition* definition;
 	// Set if a new element definition should be fetched from the style.
 	bool definition_dirty;
 	// Set if a child element has a dirty style definition
 	bool child_definition_dirty;
+	// cached non-inherited properties
+	ElementStyleCache *cache;
 };
 
 }

+ 341 - 0
Source/Core/ElementStyleCache.cpp

@@ -0,0 +1,341 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include "ElementStyle.h"
+#include "ElementStyleCache.h"
+
+namespace Rocket {
+namespace Core {
+
+ElementStyleCache::ElementStyleCache(ElementStyle *style) : style(style), 
+	border_top_width(NULL), border_bottom_width(NULL), border_left_width(NULL), border_right_width(NULL),
+	margin_top(NULL), margin_bottom(NULL), margin_left(NULL), margin_right(NULL),
+	padding_top(NULL), padding_bottom(NULL), padding_left(NULL), padding_right(NULL),
+	width(NULL), height(NULL),
+	local_width(NULL), local_height(NULL), have_local_width(false), have_local_height(false),
+	overflow_x(NULL), overflow_y(NULL),
+	position(-1), float_(-1), display(-1), whitespace(-1),
+	line_height(NULL), text_align(-1), text_transform(-1), vertical_align(NULL)
+{
+}
+
+void ElementStyleCache::Clear()
+{
+	ClearBorder();
+	ClearMargin();
+	ClearPadding();
+	ClearDimensions();
+	ClearOverflow();
+	ClearPosition();
+	ClearFloat();
+	ClearDisplay();
+	ClearWhitespace();
+}
+
+void ElementStyleCache::ClearInherited()
+{
+	ClearLineHeight();
+	ClearTextAlign();
+	ClearTextTransform();
+	ClearVerticalAlign();
+}
+
+void ElementStyleCache::ClearBorder()
+{
+	border_top_width = border_bottom_width = border_left_width = border_right_width = NULL;
+}
+
+void ElementStyleCache::ClearMargin()
+{
+	margin_top = margin_bottom = margin_left = margin_right = NULL;
+}
+
+void ElementStyleCache::ClearPadding()
+{
+	padding_top = padding_bottom = padding_left = padding_right = NULL;
+}
+
+void ElementStyleCache::ClearDimensions()
+{
+	width = height = NULL;
+	have_local_width = have_local_height = false;
+}
+
+void ElementStyleCache::ClearOverflow()
+{
+	overflow_x = overflow_y = -1;
+}
+
+void ElementStyleCache::ClearPosition()
+{
+	position = -1;
+}
+
+void ElementStyleCache::ClearFloat()
+{
+	float_ = -1;
+}
+
+void ElementStyleCache::ClearDisplay()
+{
+	display = -1;
+}
+
+void ElementStyleCache::ClearWhitespace()
+{
+	whitespace = -1;
+}
+
+void ElementStyleCache::ClearLineHeight()
+{
+	line_height = NULL;
+}
+
+void ElementStyleCache::ClearTextAlign()
+{
+	text_align = -1;
+}
+
+void ElementStyleCache::ClearTextTransform()
+{
+	text_transform = -1;
+}
+
+void ElementStyleCache::ClearVerticalAlign()
+{
+	vertical_align = NULL;
+}
+
+void ElementStyleCache::GetBorderWidthProperties(const Property **o_border_top_width, const Property **o_border_bottom_width, const Property **o_border_left_width, const Property **o_border_right_width)
+{
+	if (o_border_top_width)
+	{
+		if (!border_top_width)
+			border_top_width = style->GetProperty(BORDER_TOP_WIDTH);
+		*o_border_top_width = border_top_width;
+	}
+
+	if (o_border_bottom_width)
+	{
+		if (!border_bottom_width)
+			border_bottom_width = style->GetProperty(BORDER_BOTTOM_WIDTH);
+		*o_border_bottom_width = border_top_width;
+	}
+
+	if (o_border_left_width)
+	{
+		if (!border_left_width)
+			border_left_width = style->GetProperty(BORDER_LEFT_WIDTH);
+		*o_border_left_width = border_left_width;
+	}
+
+	if (o_border_right_width)
+	{
+		if (!border_right_width)
+			border_right_width = style->GetProperty(BORDER_RIGHT_WIDTH);
+		*o_border_right_width = border_right_width;
+	}
+}
+
+void ElementStyleCache::GetMarginProperties(const Property **o_margin_top, const Property **o_margin_bottom, const Property **o_margin_left, const Property **o_margin_right)
+{
+	if (o_margin_top)
+	{
+		if (!margin_top)
+			margin_top = style->GetProperty(MARGIN_TOP);
+		*o_margin_top = margin_top;
+	}
+
+	if (o_margin_bottom)
+	{
+		if (!margin_bottom)
+			margin_bottom = style->GetProperty(MARGIN_BOTTOM);
+		*o_margin_bottom = margin_bottom;
+	}
+
+	if (o_margin_left)
+	{
+		if (!margin_left)
+			margin_left = style->GetProperty(MARGIN_LEFT);
+		*o_margin_left = margin_left;
+	}
+
+	if (o_margin_right)
+	{
+		if (!margin_right)
+			margin_right = style->GetProperty(MARGIN_RIGHT);
+		*o_margin_right = margin_right;
+	}
+}
+
+void ElementStyleCache::GetPaddingProperties(const Property **o_padding_top, const Property **o_padding_bottom, const Property **o_padding_left, const Property **o_padding_right)
+{
+	if (o_padding_top)
+	{
+		if (!padding_top)
+			padding_top = style->GetProperty(PADDING_TOP);
+		*o_padding_top = padding_top;
+	}
+
+	if (o_padding_bottom)
+	{
+		if (!padding_bottom)
+			padding_bottom = style->GetProperty(PADDING_BOTTOM);
+		*o_padding_bottom = padding_bottom;
+	}
+
+	if (o_padding_left)
+	{
+		if (!padding_left)
+			padding_left = style->GetProperty(PADDING_LEFT);
+		*o_padding_left = padding_left;
+	}
+
+	if (o_padding_right)
+	{
+		if (!padding_right)
+			padding_right = style->GetProperty(PADDING_RIGHT);
+		*o_padding_right = padding_right;
+	}
+}
+
+void ElementStyleCache::GetDimensionProperties(const Property **o_width, const Property **o_height)
+{
+	if (o_width)
+	{
+		if (!width)
+			width = style->GetProperty(WIDTH);
+		*o_width = width;
+	}
+
+	if (o_height)
+	{
+		if (!height)
+			height = style->GetProperty(HEIGHT);
+		*o_height = height;
+	}
+}
+
+void ElementStyleCache::GetLocalDimensionProperties(const Property **o_width, const Property **o_height)
+{
+	if (o_width)
+	{
+		if (!have_local_width)
+		{
+			have_local_width = true;
+			local_width = style->GetLocalProperty(WIDTH);
+		}
+		*o_width = local_width;
+	}
+
+	if (o_height)
+	{
+		if (!have_local_height)
+		{
+			have_local_height = true;
+			local_height = style->GetLocalProperty(HEIGHT);
+		}
+		*o_height = local_height;
+	}
+}
+
+void ElementStyleCache::GetOverflow(int *o_overflow_x, int *o_overflow_y)
+{
+	if (o_overflow_x)
+	{
+		if (overflow_x < 0)
+			overflow_x = style->GetProperty(OVERFLOW_X)->Get< int >();
+		*o_overflow_x = overflow_x;
+	}
+
+	if (o_overflow_y)
+	{
+		if (overflow_y < 0)
+			overflow_y = style->GetProperty(OVERFLOW_Y)->Get< int >();
+		*o_overflow_y = overflow_y;
+	}
+}
+
+int ElementStyleCache::GetPosition()
+{
+	if (position < 0)
+		position = style->GetProperty(POSITION)->Get< int >();
+	return position;
+}
+
+int ElementStyleCache::GetFloat()
+{
+	if (float_ < 0)
+		float_ = style->GetProperty(FLOAT)->Get< int >();
+	return float_;
+}
+
+int ElementStyleCache::GetDisplay()
+{
+	if (display < 0)
+		display = style->GetProperty(DISPLAY)->Get< int >();
+	return display;
+}
+
+int ElementStyleCache::GetWhitespace()
+{
+	if (whitespace < 0)
+		whitespace = style->GetProperty(WHITE_SPACE)->Get< int >();
+	return whitespace;
+}
+
+const Property *ElementStyleCache::GetLineHeightProperty()
+{
+	if (!line_height)
+		line_height = style->GetProperty(LINE_HEIGHT);
+	return line_height;
+}
+
+int ElementStyleCache::GetTextAlign()
+{
+	if (text_align < 0)
+		text_align = style->GetProperty(TEXT_ALIGN)->Get< int >();
+	return text_align;
+}
+
+int ElementStyleCache::GetTextTransform()
+{
+	if (text_transform < 0)
+		text_transform = style->GetProperty(TEXT_TRANSFORM)->Get< int >();
+	return text_transform;
+}
+
+const Property *ElementStyleCache::GetVerticalAlignProperty()
+{
+	if (!vertical_align)
+		vertical_align = style->GetProperty(VERTICAL_ALIGN);
+	return vertical_align;
+}
+
+}
+}

+ 130 - 0
Source/Core/ElementStyleCache.h

@@ -0,0 +1,130 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCOREELEMENTSTYLECACHE_H
+#define ROCKETCOREELEMENTSTYLECACHE_H
+
+#include "ElementDefinition.h"
+#include <Rocket/Core/Types.h>
+
+namespace Rocket {
+namespace Core {
+
+class ElementStyle;
+
+/**
+	Manages caching of layout-important properties and provides
+	O(1) access to them (note that for invalidated cache, the access
+	time is still O(log(N)) as per standard std::map).
+	@author Victor Luchits
+ */
+
+class ElementStyleCache
+{
+public:
+	ElementStyleCache(ElementStyle *style);
+
+	/// Invalidation function for all non-inherited properties
+	void Clear();
+
+	/// Invalidation function for all inherited properties
+	void ClearInherited();
+
+	/// Invalidation functions for individual and grouped non-inherited properties
+	void ClearBorder();
+	void ClearMargin();
+	void ClearPadding();
+	void ClearDimensions();
+	void ClearPosition();
+	void ClearFloat();
+	void ClearDisplay();
+	void ClearWhitespace();
+	void ClearOverflow();
+
+	/// Invalidation functions for individual and grouped inherited properties
+	void ClearLineHeight();
+	void ClearTextAlign();
+	void ClearTextTransform();
+	void ClearVerticalAlign();
+
+	/// Returns 'border-width' properties from element's style or local cache.
+	void GetBorderWidthProperties(const Property **border_top_width, const Property **border_bottom_width, const Property **border_left_width, const Property **border_right_width);
+	/// Returns 'margin' properties from element's style or local cache.
+	void GetMarginProperties(const Property **margin_top, const Property **margin_bottom, const Property **margin_left, const Property **margin_right);
+	/// Returns 'padding' properties from element's style or local cache.
+	void GetPaddingProperties(const Property **padding_top, const Property **padding_bottom, const Property **padding_left, const Property **padding_right);
+	/// Returns 'width' and 'height' properties from element's style or local cache.
+	void GetDimensionProperties(const Property **width, const Property **height);
+	/// Returns local 'width' and 'height' properties from element's style or local cache,
+	/// ignoring default values.
+	void GetLocalDimensionProperties(const Property **width, const Property **height);
+	/// Returns 'overflow' properties' values from element's style or local cache.
+	void GetOverflow(int *overflow_x, int *overflow_y);
+	/// Returns 'position' property value from element's style or local cache.
+	int GetPosition();
+	/// Returns 'float' property value from element's style or local cache.
+	int GetFloat();
+	/// Returns 'display' property value from element's style or local cache.
+	int GetDisplay();
+	/// Returns 'white-space' property value from element's style or local cache.
+	int GetWhitespace();
+
+	/// Returns 'line-height' property value from element's style or local cache.
+	const Property *GetLineHeightProperty();
+	/// Returns 'text-align' property value from element's style or local cache.
+	int GetTextAlign();
+	/// Returns 'text-transform' property value from element's style or local cache.
+	int GetTextTransform();
+	/// Returns 'vertical-align' property value from element's style or local cache.
+	const Property *GetVerticalAlignProperty();
+
+private:
+	/// Element style that owns this cache instance.
+	ElementStyle *style;
+
+	/// Cached properties.
+	const Property *border_top_width, *border_bottom_width, *border_left_width, *border_right_width;
+	const Property *margin_top, *margin_bottom, *margin_left, *margin_right;
+	const Property *padding_top, *padding_bottom, *padding_left, *padding_right;
+	const Property *width, *height;
+	const Property *local_width, *local_height;
+	bool have_local_width, have_local_height;
+	int overflow_x, overflow_y;
+	int position;
+	int float_;
+	int display;
+	int whitespace;
+	const Property *line_height;
+	int text_align;
+	int text_transform;
+	const Property *vertical_align;
+};
+
+}
+}
+
+#endif

+ 4 - 4
Source/Core/ElementTextDefault.cpp

@@ -149,7 +149,7 @@ bool ElementTextDefault::GenerateToken(float& token_width, int line_begin)
 		return 0;
 
 	// Determine how we are processing white-space while formatting the text.
-	int white_space_property = GetProperty< int >(WHITE_SPACE);
+	int white_space_property = GetWhitespace();
 	bool collapse_white_space = white_space_property == WHITE_SPACE_NORMAL ||
 								white_space_property == WHITE_SPACE_NOWRAP ||
 								white_space_property == WHITE_SPACE_PRE_LINE;
@@ -160,7 +160,7 @@ bool ElementTextDefault::GenerateToken(float& token_width, int line_begin)
 	const word* token_begin = text.CString() + line_begin;
 	WString token;
 
-	BuildToken(token, token_begin, text.CString() + text.Length(), true, collapse_white_space, break_at_endline, GetProperty< int >(TEXT_TRANSFORM));
+	BuildToken(token, token_begin, text.CString() + text.Length(), true, collapse_white_space, break_at_endline, GetTextTransform());
 	token_width = (float) font_face_handle->GetStringWidth(token, 0);
 
 	return LastToken(token_begin, text.CString() + text.Length(), collapse_white_space, break_at_endline);
@@ -181,7 +181,7 @@ bool ElementTextDefault::GenerateLine(WString& line, int& line_length, float& li
 		return true;
 
 	// Determine how we are processing white-space while formatting the text.
-	int white_space_property = GetProperty< int >(WHITE_SPACE);
+	int white_space_property = GetWhitespace();
 	bool collapse_white_space = white_space_property == WHITE_SPACE_NORMAL ||
 								white_space_property == WHITE_SPACE_NOWRAP ||
 								white_space_property == WHITE_SPACE_PRE_LINE;
@@ -194,7 +194,7 @@ bool ElementTextDefault::GenerateLine(WString& line, int& line_length, float& li
 							white_space_property == WHITE_SPACE_PRE_LINE;
 
 	// Determine what (if any) text transformation we are putting the characters through.
-	int text_transform_property = GetProperty< int >(TEXT_TRANSFORM);
+	int text_transform_property = GetTextTransform();
 
 	// Starting at the line_begin character, we generate sections of the text (we'll call them tokens) depending on the
 	// white-space parsing parameters. Each section is then appended to the line if it can fit. If not, or if an

+ 10 - 22
Source/Core/ElementUtilities.cpp

@@ -141,7 +141,7 @@ int ElementUtilities::GetLineHeight(Element* element)
 		return 0;
 
 	int line_height = font_face_handle->GetLineHeight();
-	const Property* line_height_property = element->GetProperty(LINE_HEIGHT);
+	const Property* line_height_property = element->GetLineHeightProperty();
 
 	// If the property is a straight number or an em measurement, then it scales the line height.
 	if (line_height_property->unit == Property::NUMBER ||
@@ -210,29 +210,14 @@ bool ElementUtilities::GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_d
 			// Ignore nodes that don't clip.
 			if (clipping_element->GetClientWidth() < clipping_element->GetScrollWidth()
 				|| clipping_element->GetClientHeight() < clipping_element->GetScrollHeight())
-			{
+			{				
 				Vector2f element_origin_f = clipping_element->GetAbsoluteOffset(Box::CONTENT);
 				Vector2f element_dimensions_f = clipping_element->GetBox().GetSize(Box::CONTENT);
-
+				
 				Vector2i element_origin(Math::RealToInteger(element_origin_f.x), Math::RealToInteger(element_origin_f.y));
 				Vector2i element_dimensions(Math::RealToInteger(element_dimensions_f.x), Math::RealToInteger(element_dimensions_f.y));
-
-				bool clip_x = clipping_element->GetProperty(OVERFLOW_X)->Get< int >() != OVERFLOW_VISIBLE;
-				bool clip_y = clipping_element->GetProperty(OVERFLOW_Y)->Get< int >() != OVERFLOW_VISIBLE;
-				ROCKET_ASSERT(clip_x || clip_y);
 				
-				if (!clip_x)
-				{
-					element_origin.x = 0;
-					element_dimensions.x = clip_dimensions.x < 0 ? element->GetContext()->GetDimensions().x : clip_dimensions.x;
-				}
-				else if (!clip_y)
-				{
-					element_origin.y = 0;
-					element_dimensions.y = clip_dimensions.y < 0 ? element->GetContext()->GetDimensions().y : clip_dimensions.y;
-				}
-
-				if (clip_dimensions == Vector2i(-1, -1))
+				if (clip_origin == Vector2i(-1, -1) && clip_dimensions == Vector2i(-1, -1))
 				{
 					clip_origin = element_origin;
 					clip_dimensions = element_dimensions;
@@ -241,10 +226,10 @@ bool ElementUtilities::GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_d
 				{
 					Vector2i top_left(Math::Max(clip_origin.x, element_origin.x),
 									  Math::Max(clip_origin.y, element_origin.y));
-
+					
 					Vector2i bottom_right(Math::Min(clip_origin.x + clip_dimensions.x, element_origin.x + element_dimensions.x),
 										  Math::Min(clip_origin.y + clip_dimensions.y, element_origin.y + element_dimensions.y));
-
+					
 					clip_origin = top_left;
 					clip_dimensions.x = Math::Max(0, bottom_right.x - top_left.x);
 					clip_dimensions.y = Math::Max(0, bottom_right.y - top_left.y);
@@ -434,7 +419,10 @@ static void SetBox(Element* element)
 
 	Box box;
 	LayoutEngine::BuildBox(box, containing_block, element);
-	if (element->GetLocalProperty(HEIGHT) == NULL)
+
+	const Property *local_height;
+	element->GetLocalDimensionProperties(NULL, &local_height);
+	if (local_height == NULL)
 		box.SetContent(Vector2f(box.GetSize().x, containing_block.y));
 
 	element->SetBox(box);

+ 4 - 5
Source/Core/LayoutBlockBox.cpp

@@ -71,7 +71,7 @@ LayoutBlockBox::LayoutBlockBox(LayoutEngine* _layout_engine, LayoutBlockBox* _pa
 	// Determine the offset parent for our children.
 	if (parent != NULL &&
 		parent->offset_parent->GetElement() != NULL &&
-		(element == NULL || element->GetProperty< int >(POSITION) == POSITION_STATIC))
+		(element == NULL || element->GetPosition() == POSITION_STATIC))
 		offset_parent = parent->offset_parent;
 	else
 		offset_parent = this;
@@ -100,11 +100,10 @@ LayoutBlockBox::LayoutBlockBox(LayoutEngine* _layout_engine, LayoutBlockBox* _pa
 
 	if (element != NULL)
 	{
-		wrap_content = element->GetProperty< int >(WHITE_SPACE) != WHITE_SPACE_NOWRAP;
+		wrap_content = element->GetWhitespace() != WHITE_SPACE_NOWRAP;
 
 		// Determine if this element should have scrollbars or not, and create them if so.
-		overflow_x_property = element->GetProperty< int >(OVERFLOW_X);
-		overflow_y_property = element->GetProperty< int >(OVERFLOW_Y);
+		element->GetOverflow(&overflow_x_property, &overflow_y_property);
 
 		if (overflow_x_property == OVERFLOW_SCROLL)
 			element->GetElementScroll()->EnableScrollbar(ElementScroll::HORIZONTAL, box.GetSize(Box::PADDING).x);
@@ -266,7 +265,7 @@ LayoutBlockBox::CloseResult LayoutBlockBox::Close()
 	if (context == BLOCK &&
 		element != NULL)
 	{
-		if (element->GetProperty< int >(POSITION) != POSITION_STATIC)
+		if (element->GetPosition() != POSITION_STATIC)
 			CloseAbsoluteElements();
 	}
 

+ 1 - 1
Source/Core/LayoutBlockBoxSpace.cpp

@@ -66,7 +66,7 @@ void LayoutBlockBoxSpace::PositionBox(Vector2f& box_position, float& box_width,
 float LayoutBlockBoxSpace::PositionBox(float cursor, Element* element)
 {
 	Vector2f element_size = element->GetBox().GetSize(Box::MARGIN);
-	int float_property = element->GetProperty< int >(FLOAT);
+	int float_property = element->GetFloat();
 
 	// Shift the cursor down (if necessary) so it isn't placed any higher than a previously-floated box.
 	for (int i = 0; i < NUM_ANCHOR_EDGES; ++i)

+ 48 - 29
Source/Core/LayoutEngine.cpp

@@ -100,23 +100,29 @@ void LayoutEngine::BuildBox(Box& box, const Vector2f& containing_block, Element*
 	}
 
 	// Calculate the padding area.
-	float padding = element->ResolveProperty(PADDING_TOP, containing_block.x);
+	const Property *padding_top, *padding_bottom, *padding_left, *padding_right;
+	element->GetPaddingProperties (&padding_top, &padding_bottom, &padding_left, &padding_right);
+
+	float padding = element->ResolveProperty(padding_top, containing_block.x);
 	box.SetEdge(Box::PADDING, Box::TOP, Math::Max(0.0f, padding));
-	padding = element->ResolveProperty(PADDING_RIGHT, containing_block.x);
+	padding = element->ResolveProperty(padding_right, containing_block.x);
 	box.SetEdge(Box::PADDING, Box::RIGHT, Math::Max(0.0f, padding));
-	padding = element->ResolveProperty(PADDING_BOTTOM, containing_block.x);
+	padding = element->ResolveProperty(padding_bottom, containing_block.x);
 	box.SetEdge(Box::PADDING, Box::BOTTOM, Math::Max(0.0f, padding));
-	padding = element->ResolveProperty(PADDING_LEFT, containing_block.x);
+	padding = element->ResolveProperty(padding_left, containing_block.x);
 	box.SetEdge(Box::PADDING, Box::LEFT, Math::Max(0.0f, padding));
 
 	// Calculate the border area.
-	float border = element->ResolveProperty(BORDER_TOP_WIDTH, containing_block.x);
+	const Property *border_top_width, *border_bottom_width, *border_left_width, *border_right_width;
+	element->GetBorderWidthProperties (&border_top_width, &border_bottom_width, &border_left_width, &border_right_width);
+
+	float border = element->ResolveProperty(border_top_width, containing_block.x);
 	box.SetEdge(Box::BORDER, Box::TOP, Math::Max(0.0f, border));
-	border = element->ResolveProperty(BORDER_RIGHT_WIDTH, containing_block.x);
+	border = element->ResolveProperty(border_right_width, containing_block.x);
 	box.SetEdge(Box::BORDER, Box::RIGHT, Math::Max(0.0f, border));
-	border = element->ResolveProperty(BORDER_BOTTOM_WIDTH, containing_block.x);
+	border = element->ResolveProperty(border_bottom_width, containing_block.x);
 	box.SetEdge(Box::BORDER, Box::BOTTOM, Math::Max(0.0f, border));
-	border = element->ResolveProperty(BORDER_LEFT_WIDTH, containing_block.x);
+	border = element->ResolveProperty(border_left_width, containing_block.x);
 	box.SetEdge(Box::BORDER, Box::LEFT, Math::Max(0.0f, border));
 
 	// Calculate the size of the content area.
@@ -134,15 +140,17 @@ void LayoutEngine::BuildBox(Box& box, const Vector2f& containing_block, Element*
 		// The element has resized itself, so we only resize it if a RCSS width or height was set explicitly. A value of
 		// 'auto' (or 'auto-fit', ie, both keywords) means keep (or adjust) the intrinsic dimensions.
 		bool auto_width = false, auto_height = false;
-		const Property* width_property = element->GetProperty(WIDTH);
+		const Property* width_property, *height_property;
+
+		element->GetDimensionProperties(&width_property, &height_property);
+
 		if (width_property->unit != Property::KEYWORD)
-			content_area.x = element->ResolveProperty(WIDTH, containing_block.x);
+			content_area.x = element->ResolveProperty(width_property, containing_block.x);
 		else
 			auto_width = true;
 
-		const Property* height_property = element->GetProperty(HEIGHT);
 		if (height_property->unit != Property::KEYWORD)
-			content_area.y = element->ResolveProperty(HEIGHT, containing_block.y);
+			content_area.y = element->ResolveProperty(height_property, containing_block.y);
 		else
 			auto_height = true;
 
@@ -181,10 +189,13 @@ void LayoutEngine::BuildBox(Box& box, const Vector2f& containing_block, Element*
 		box.SetContent(content_area);
 
 		// Evaluate the margins. Any declared as 'auto' will resolve to 0.
-		box.SetEdge(Box::MARGIN, Box::TOP, element->ResolveProperty(MARGIN_TOP, containing_block.x));
-		box.SetEdge(Box::MARGIN, Box::RIGHT, element->ResolveProperty(MARGIN_RIGHT, containing_block.x));
-		box.SetEdge(Box::MARGIN, Box::BOTTOM, element->ResolveProperty(MARGIN_BOTTOM, containing_block.x));
-		box.SetEdge(Box::MARGIN, Box::LEFT, element->ResolveProperty(MARGIN_LEFT, containing_block.x));
+		const Property *margin_top, *margin_bottom, *margin_left, *margin_right;
+		element->GetMarginProperties(&margin_top, &margin_bottom, &margin_left, &margin_right);
+
+		box.SetEdge(Box::MARGIN, Box::TOP, element->ResolveProperty(margin_top, containing_block.x));
+		box.SetEdge(Box::MARGIN, Box::RIGHT, element->ResolveProperty(margin_right, containing_block.x));
+		box.SetEdge(Box::MARGIN, Box::BOTTOM, element->ResolveProperty(margin_bottom, containing_block.x));
+		box.SetEdge(Box::MARGIN, Box::LEFT, element->ResolveProperty(margin_left, containing_block.x));
 	}
 
 	// The element is block, so we need to run the box through the ringer to potentially evaluate auto margins and
@@ -295,13 +306,13 @@ bool LayoutEngine::FormatElement(Element* element)
 		return true;
 
 	// Fetch the display property, and don't lay this element out if it is set to a display type of none.
-	int display_property = element->GetProperty< int >(DISPLAY);
+	int display_property = element->GetDisplay();
 	if (display_property == DISPLAY_NONE)
 		return true;
 
 	// Check for an absolute position; if this has been set, then we remove it from the flow and add it to the current
 	// block box to be laid out and positioned once the block has been closed and sized.
-	int position_property = element->GetProperty< int >(POSITION);
+	int position_property = element->GetPosition();
 	if (position_property == POSITION_ABSOLUTE ||
 		position_property == POSITION_FIXED)
 	{
@@ -311,7 +322,7 @@ bool LayoutEngine::FormatElement(Element* element)
 	}
 
 	// If the element is floating, we remove it from the flow.
-	int float_property = element->GetProperty< int >(FLOAT);
+	int float_property = element->GetFloat();
 	if (float_property != FLOAT_NONE)
 	{
 		// Format the element as a block element.
@@ -469,7 +480,8 @@ void LayoutEngine::BuildBoxWidth(Box& box, Element* element, float containing_bl
 		width_auto = false;
 	else
 	{
-		const Property* width_property = element->GetProperty(WIDTH);
+		const Property* width_property;
+		element->GetDimensionProperties(&width_property, NULL);
 		if (width_property->unit == Property::KEYWORD)
 		{
 			width_auto = true;
@@ -477,17 +489,20 @@ void LayoutEngine::BuildBoxWidth(Box& box, Element* element, float containing_bl
 		else
 		{
 			width_auto = false;
-			content_area.x = element->ResolveProperty(WIDTH, containing_block_width);
+			content_area.x = element->ResolveProperty(width_property, containing_block_width);
 		}
 	}
 
 	// Determine if the element has automatic margins.
 	bool margins_auto[2];
 	int num_auto_margins = 0;
+
+	const Property *margin_left, *margin_right;
+	element->GetMarginProperties(NULL, NULL, &margin_left, &margin_right);
+
 	for (int i = 0; i < 2; ++i)
 	{
-		const String& property_name = i == 0 ? MARGIN_LEFT : MARGIN_RIGHT;
-		const Property* margin_property = element->GetLocalProperty(property_name);
+		const Property* margin_property = i == 0 ? margin_left : margin_right;
 		if (margin_property != NULL &&
 			margin_property->unit == Property::KEYWORD)
 		{
@@ -497,7 +512,7 @@ void LayoutEngine::BuildBoxWidth(Box& box, Element* element, float containing_bl
 		else
 		{
 			margins_auto[i] = false;
-			box.SetEdge(Box::MARGIN, i == 0 ? Box::LEFT : Box::RIGHT, element->ResolveProperty(property_name, containing_block_width));
+			box.SetEdge(Box::MARGIN, i == 0 ? Box::LEFT : Box::RIGHT, element->ResolveProperty(margin_property, containing_block_width));
 		}
 	}
 
@@ -561,7 +576,8 @@ void LayoutEngine::BuildBoxHeight(Box& box, Element* element, float containing_b
 		height_auto = false;
 	else
 	{
-		const Property* height_property = element->GetProperty(HEIGHT);
+		const Property* height_property;
+		element->GetDimensionProperties(NULL, &height_property);
 		if (height_property == NULL)
 		{
 			height_auto = false;		
@@ -573,17 +589,20 @@ void LayoutEngine::BuildBoxHeight(Box& box, Element* element, float containing_b
 		else
 		{
 			height_auto = false;
-			content_area.y = element->ResolveProperty(HEIGHT, containing_block_height);
+			content_area.y = element->ResolveProperty(height_property, containing_block_height);
 		}
 	}
 
 	// Determine if the element has automatic margins.
 	bool margins_auto[2];
 	int num_auto_margins = 0;
+
+	const Property *margin_top, *margin_bottom;
+	element->GetMarginProperties(&margin_top, &margin_bottom, NULL, NULL);
+
 	for (int i = 0; i < 2; ++i)
 	{
-		const String& property_name = i == 0 ? MARGIN_TOP : MARGIN_BOTTOM;
-		const Property* margin_property = element->GetLocalProperty(property_name);
+		const Property* margin_property = i == 0 ? margin_top : margin_bottom;
 		if (margin_property != NULL &&
 			margin_property->unit == Property::KEYWORD)
 		{
@@ -593,7 +612,7 @@ void LayoutEngine::BuildBoxHeight(Box& box, Element* element, float containing_b
 		else
 		{
 			margins_auto[i] = false;
-			box.SetEdge(Box::MARGIN, i == 0 ? Box::TOP : Box::BOTTOM, element->ResolveProperty(property_name, containing_block_height));
+			box.SetEdge(Box::MARGIN, i == 0 ? Box::TOP : Box::BOTTOM, element->ResolveProperty(margin_property, containing_block_height));
 		}
 	}
 

+ 2 - 2
Source/Core/LayoutInlineBox.cpp

@@ -70,7 +70,7 @@ LayoutInlineBox::LayoutInlineBox(Element* _element, const Box& _box) : box(_box)
 		}
 	}
 
-	const Property* property = element->GetProperty(VERTICAL_ALIGN);
+	const Property* property = element->GetVerticalAlignProperty();
 	if (property->unit == Property::KEYWORD)
 		vertical_align_property = property->value.Get< int >();
 	else
@@ -239,7 +239,7 @@ void LayoutInlineBox::CalculateBaseline(float& ascender, float& descender)
 		// The baseline of this box is offset by a fixed amount from its parent's baseline.
 		default:
 		{
-			SetVerticalPosition(-1 * element->ResolveProperty(VERTICAL_ALIGN, GetParentLineHeight()));
+			SetVerticalPosition(-1 * element->ResolveProperty(element->GetVerticalAlignProperty(), GetParentLineHeight()));
 		}
 		break;
 	}

+ 1 - 1
Source/Core/LayoutLineBox.cpp

@@ -140,7 +140,7 @@ LayoutInlineBox* LayoutLineBox::Close(LayoutInlineBox* overflow)
 
 	// Position all the boxes horizontally in the line. We only need to reposition the elements if they're set to
 	// centre or right; the element are already placed left-aligned, and justification occurs at the text level.
-	int text_align_property = parent->GetParent()->GetElement()->GetProperty(TEXT_ALIGN)->value.Get< int >();
+	int text_align_property = parent->GetParent()->GetElement()->GetTextAlign();
 	if (text_align_property == TEXT_ALIGN_CENTER ||
 		text_align_property == TEXT_ALIGN_RIGHT)
 	{

+ 1 - 1
Source/Core/StyleSheetNodeSelectorEmpty.cpp

@@ -46,7 +46,7 @@ bool StyleSheetNodeSelectorEmpty::IsApplicable(const Element* element, int ROCKE
 {
 	for (int i = 0; i < element->GetNumChildren(); ++i)
 	{
-		if (element->GetChild(i)->GetProperty< int >(DISPLAY) != DISPLAY_NONE)
+		if (element->GetChild(i)->GetDisplay() != DISPLAY_NONE)
 			return false;
 	}
 

+ 1 - 1
Source/Core/StyleSheetNodeSelectorFirstChild.cpp

@@ -58,7 +58,7 @@ bool StyleSheetNodeSelectorFirstChild::IsApplicable(const Element* element, int
 
 		// If this child is not a text element, then the selector fails; this element is non-trivial.
 		if (dynamic_cast< ElementText* >(child) == NULL &&
-			child->GetProperty< int >(DISPLAY) != DISPLAY_NONE)
+			child->GetDisplay() != DISPLAY_NONE)
 			return false;
 
 		// Otherwise, skip over the text element to find the last non-trivial element.

+ 1 - 1
Source/Core/StyleSheetNodeSelectorFirstOfType.cpp

@@ -59,7 +59,7 @@ bool StyleSheetNodeSelectorFirstOfType::IsApplicable(const Element* element, int
 		// Otherwise, if this child shares our element's tag, then our element is not the first tagged child; the
 		// selector fails.
 		if (child->GetTagName() == element->GetTagName() &&
-			child->GetProperty< int >(DISPLAY) != DISPLAY_NONE)
+			child->GetDisplay() != DISPLAY_NONE)
 			return false;
 
 		child_index++;

+ 1 - 1
Source/Core/StyleSheetNodeSelectorLastChild.cpp

@@ -58,7 +58,7 @@ bool StyleSheetNodeSelectorLastChild::IsApplicable(const Element* element, int R
 
 		// If this child is not a text element, then the selector fails; this element is non-trivial.
 		if (dynamic_cast< ElementText* >(child) == NULL &&
-			child->GetProperty< int >(DISPLAY) != DISPLAY_NONE)
+			child->GetDisplay() != DISPLAY_NONE)
 			return false;
 
 		// Otherwise, skip over the text element to find the last non-trivial element.

+ 1 - 1
Source/Core/StyleSheetNodeSelectorLastOfType.cpp

@@ -59,7 +59,7 @@ bool StyleSheetNodeSelectorLastOfType::IsApplicable(const Element* element, int
 		// Otherwise, if this child shares our element's tag, then our element is not the first tagged child; the
 		// selector fails.
 		if (child->GetTagName() == element->GetTagName() &&
-			child->GetProperty< int >(DISPLAY) != DISPLAY_NONE)
+			child->GetDisplay() != DISPLAY_NONE)
 			return false;
 
 		child_index--;

+ 1 - 1
Source/Core/StyleSheetNodeSelectorNthChild.cpp

@@ -64,7 +64,7 @@ bool StyleSheetNodeSelectorNthChild::IsApplicable(const Element* element, int a,
 			break;
 
 		// Skip nodes without a display type.
-		if (child->GetProperty< int >(DISPLAY) == DISPLAY_NONE)
+		if (child->GetDisplay() == DISPLAY_NONE)
 			continue;
 
 		element_index++;

+ 1 - 1
Source/Core/StyleSheetNodeSelectorNthLastChild.cpp

@@ -62,7 +62,7 @@ bool StyleSheetNodeSelectorNthLastChild::IsApplicable(const Element* element, in
 		if (child == element)
 			break;
 
-		if (child->GetProperty< int >(DISPLAY) == DISPLAY_NONE)
+		if (child->GetDisplay() == DISPLAY_NONE)
 			continue;
 
 		element_index++;

+ 1 - 1
Source/Core/StyleSheetNodeSelectorNthLastOfType.cpp

@@ -60,7 +60,7 @@ bool StyleSheetNodeSelectorNthLastOfType::IsApplicable(const Element* element, i
 
 		// Skip nodes that don't share our tag.
 		if (child->GetTagName() != element->GetTagName() ||
-			child->GetProperty< int >(DISPLAY) == DISPLAY_NONE)
+			child->GetDisplay() == DISPLAY_NONE)
 			continue;
 
 		element_index++;

+ 1 - 1
Source/Core/StyleSheetNodeSelectorNthOfType.cpp

@@ -60,7 +60,7 @@ bool StyleSheetNodeSelectorNthOfType::IsApplicable(const Element* element, int a
 
 		// Skip nodes that don't share our tag.
 		if (child->GetTagName() != element->GetTagName() ||
-			child->GetProperty< int >(DISPLAY) == DISPLAY_NONE)
+			child->GetDisplay() == DISPLAY_NONE)
 			continue;
 
 		element_index++;

+ 1 - 1
Source/Core/StyleSheetNodeSelectorOnlyChild.cpp

@@ -58,7 +58,7 @@ bool StyleSheetNodeSelectorOnlyChild::IsApplicable(const Element* element, int R
 
 		// Skip the child if it is trivial.
 		if (dynamic_cast< const ElementText* >(element) != NULL ||
-			child->GetProperty< int >(DISPLAY) == DISPLAY_NONE)
+			child->GetDisplay() == DISPLAY_NONE)
 			continue;
 
 		return false;

+ 1 - 1
Source/Core/StyleSheetNodeSelectorOnlyOfType.cpp

@@ -58,7 +58,7 @@ bool StyleSheetNodeSelectorOnlyOfType::IsApplicable(const Element* element, int
 
 		// Skip the child if it does not share our tag.
 		if (child->GetTagName() != element->GetTagName() ||
-			child->GetProperty< int >(DISPLAY) == DISPLAY_NONE)
+			child->GetDisplay() == DISPLAY_NONE)
 			continue;
 
 		// We've found a similarly-tagged child to our element; selector fails.

+ 6 - 3
Source/Core/WidgetSlider.cpp

@@ -308,10 +308,13 @@ void WidgetSlider::FormatBar(float bar_length)
 	Box bar_box;
 	LayoutEngine::BuildBox(bar_box, parent->GetBox().GetSize(), bar);
 
+	const Property *local_width, *local_height;
+	bar->GetLocalDimensionProperties(&local_width, &local_height);
+
 	Vector2f bar_box_content = bar_box.GetSize();
 	if (orientation == HORIZONTAL)
 	{
-		if (bar->GetLocalProperty(HEIGHT) == NULL)
+		if (local_height == NULL)
 			bar_box_content.y = parent->GetBox().GetSize().y;
 	}
 
@@ -323,7 +326,7 @@ void WidgetSlider::FormatBar(float bar_length)
 		{
 			float track_length = track_size.y - (bar_box.GetCumulativeEdge(Box::CONTENT, Box::TOP) + bar_box.GetCumulativeEdge(Box::CONTENT, Box::BOTTOM));
 
-			if (bar->GetLocalProperty(HEIGHT) == NULL)
+			if (local_height == NULL)
 			{
 				bar_box_content.y = track_length * bar_length;
 
@@ -344,7 +347,7 @@ void WidgetSlider::FormatBar(float bar_length)
 		{
 			float track_length = track_size.x - (bar_box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) + bar_box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT));
 
-			if (bar->GetLocalProperty(WIDTH) == NULL)
+			if (local_width == NULL)
 			{
 				bar_box_content.x = track_length * bar_length;