Browse Source

Refactor ComputedValues to reduce memory usage.

Reduces the byte size of ComputedValues to less than half of previous.

Split the computed values into common values, rare values, and inherited values. Tried a few different optimization strategies, such as using copy-on-write for the inherited and rare values. Didn't seem to make a noticable difference so for now I dropped this to avoid the added complexity. Might be worthwhile to look into this some more later.

Retrieving computed values are now done through function calls instead of member objects, so it touches a lot of files for that reason.
Michael Ragazzon 3 years ago
parent
commit
8b7388ecdc
53 changed files with 1096 additions and 721 deletions
  1. 2 0
      CMake/FileList.cmake
  2. 1 0
      Include/RmlUi/Core.h
  3. 363 210
      Include/RmlUi/Core/ComputedValues.h
  4. 1 1
      Include/RmlUi/Core/Core.h
  5. 4 4
      Include/RmlUi/Core/Element.h
  6. 1 1
      Include/RmlUi/Core/ElementUtilities.h
  7. 2 2
      Include/RmlUi/Core/FontEngineInterface.h
  8. 1 1
      Include/RmlUi/Core/GeometryUtilities.h
  9. 152 0
      Include/RmlUi/Core/StyleTypes.h
  10. 16 26
      Source/Core/ComputeProperty.cpp
  11. 3 1
      Source/Core/ComputeProperty.h
  12. 89 0
      Source/Core/ComputedValues.cpp
  13. 9 8
      Source/Core/Context.cpp
  14. 6 5
      Source/Core/DecoratorGradient.cpp
  15. 3 2
      Source/Core/DecoratorNinePatch.cpp
  16. 2 2
      Source/Core/DecoratorTiled.cpp
  17. 97 77
      Source/Core/Element.cpp
  18. 8 12
      Source/Core/ElementBackgroundBorder.cpp
  19. 2 1
      Source/Core/ElementDecoration.cpp
  20. 11 11
      Source/Core/ElementDocument.cpp
  21. 6 5
      Source/Core/ElementHandle.cpp
  22. 5 4
      Source/Core/ElementScroll.cpp
  23. 113 157
      Source/Core/ElementStyle.cpp
  24. 9 9
      Source/Core/ElementText.cpp
  25. 6 6
      Source/Core/ElementUtilities.cpp
  26. 7 6
      Source/Core/Elements/ElementImage.cpp
  27. 7 6
      Source/Core/Elements/ElementProgress.cpp
  28. 2 1
      Source/Core/Elements/WidgetDropDown.cpp
  29. 2 1
      Source/Core/Elements/WidgetSlider.cpp
  30. 9 8
      Source/Core/Elements/WidgetTextInput.cpp
  31. 1 1
      Source/Core/FontEngineDefault/FontFace.h
  32. 1 0
      Source/Core/FontEngineDefault/FontFamily.cpp
  33. 1 1
      Source/Core/FontEngineDefault/FontProvider.h
  34. 2 2
      Source/Core/FontEngineDefault/FontTypes.h
  35. 1 0
      Source/Core/FontEngineDefault/FreeTypeInterface.cpp
  36. 13 12
      Source/Core/LayoutBlockBox.cpp
  37. 5 4
      Source/Core/LayoutBlockBoxSpace.cpp
  38. 1 1
      Source/Core/LayoutBlockBoxSpace.h
  39. 48 49
      Source/Core/LayoutDetails.cpp
  40. 1 1
      Source/Core/LayoutDetails.h
  41. 6 5
      Source/Core/LayoutEngine.cpp
  42. 17 16
      Source/Core/LayoutFlex.cpp
  43. 4 3
      Source/Core/LayoutInlineBox.cpp
  44. 1 1
      Source/Core/LayoutInlineBox.h
  45. 10 20
      Source/Core/LayoutInlineBoxText.cpp
  46. 6 5
      Source/Core/LayoutLineBox.cpp
  47. 11 10
      Source/Core/LayoutTable.cpp
  48. 3 2
      Source/Core/LayoutTableDetails.cpp
  49. 1 1
      Source/Core/LayoutTableDetails.h
  50. 3 2
      Source/Core/StyleSheetContainer.cpp
  51. 9 8
      Source/Core/WidgetScroll.cpp
  52. 6 5
      Source/Lottie/ElementLottie.cpp
  53. 6 5
      Source/SVG/ElementSVG.cpp

+ 2 - 0
CMake/FileList.cmake

@@ -210,6 +210,7 @@ set(Core_PUB_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/StyleSheetContainer.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/StyleSheetSpecification.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/StyleSheetTypes.h
+    ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/StyleTypes.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/SystemInterface.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Texture.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Traits.h
@@ -238,6 +239,7 @@ set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/BaseXMLParser.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Box.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Clock.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ComputedValues.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/ComputeProperty.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Context.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancer.cpp

+ 1 - 0
Include/RmlUi/Core.h

@@ -81,6 +81,7 @@
 #include "Core/StyleSheet.h"
 #include "Core/StyleSheetContainer.h"
 #include "Core/StyleSheetSpecification.h"
+#include "Core/StyleTypes.h"
 #include "Core/SystemInterface.h"
 #include "Core/Texture.h"
 #include "Core/Transform.h"

+ 363 - 210
Include/RmlUi/Core/ComputedValues.h

@@ -14,7 +14,7 @@
  *
  * 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
@@ -28,229 +28,382 @@
 #ifndef RMLUI_CORE_COMPUTEDVALUES_H
 #define RMLUI_CORE_COMPUTEDVALUES_H
 
-#include "Types.h"
 #include "Animation.h"
+#include "Element.h"
+#include "StyleTypes.h"
+#include "Types.h"
 
 namespace Rml {
 namespace Style {
 
-struct LengthPercentageAuto {
-	enum Type { Auto, Length, Percentage } type = Length;
-	float value = 0;
-	LengthPercentageAuto() {}
-	LengthPercentageAuto(Type type, float value = 0) : type(type), value(value) {}
-};
-struct LengthPercentage {
-	enum Type { Length, Percentage } type = Length;
-	float value = 0;
-	LengthPercentage() {}
-	LengthPercentage(Type type, float value = 0) : type(type), value(value) {}
-};
-
-struct NumberAuto {
-	enum Type { Auto, Number } type = Number;
-	float value = 0;
-	NumberAuto() {}
-	NumberAuto(Type type, float value = 0) : type(type), value(value) {}
-};
-
-
-using Margin = LengthPercentageAuto;
-using Padding = LengthPercentage;
-
-enum class Display : uint8_t { None, Block, Inline, InlineBlock, Flex, Table, TableRow, TableRowGroup, TableColumn, TableColumnGroup, TableCell };
-enum class Position : uint8_t { Static, Relative, Absolute, Fixed };
-
-using Top = LengthPercentageAuto;
-using Right = LengthPercentageAuto;
-using Bottom = LengthPercentageAuto;
-using Left = LengthPercentageAuto;
-
-enum class Float : uint8_t { None, Left, Right };
-enum class Clear : uint8_t { None, Left, Right, Both };
-
-enum class BoxSizing : uint8_t { ContentBox, BorderBox };
-
-using ZIndex = NumberAuto;
-
-using Width = LengthPercentageAuto;
-using MinWidth = LengthPercentage;
-using MaxWidth = LengthPercentage;
-
-using Height = LengthPercentageAuto;
-using MinHeight = LengthPercentage;
-using MaxHeight = LengthPercentage;
-
-struct LineHeight {
-	float value = 12.f * 1.2f; // The computed value (length)
-	enum InheritType { Number, Length } inherit_type = Number;
-	float inherit_value = 1.2f;
-	LineHeight() {}
-	LineHeight(float value, InheritType inherit_type, float inherit_value) : value(value), inherit_type(inherit_type), inherit_value(inherit_value) {}
-};
-struct VerticalAlign {
-	enum Type { Baseline, Middle, Sub, Super, TextTop, TextBottom, Top, Bottom, Length } type;
-	float value; // For length type
-	VerticalAlign(Type type = Baseline) : type(type), value(0) {}
-	VerticalAlign(float value) : type(Length), value(value) {}
-};
-
-enum class Overflow : uint8_t { Visible, Hidden, Auto, Scroll };
-struct Clip {
-private:
-	// Here, 'value' is encoded with Auto <=> 0, None <=> -1, Always <=> -2. A value > 0 means the given number.
-	int8_t value = 0;
-
-public:
-	// The Type enum must instead correspond to the keywords in StyleSheetSpec.
-	enum class Type : uint8_t { Auto, None, Always, Number };
-	Clip() {}
-	Clip(Type type, int8_t number = 0) : value(type == Type::Auto ? 0 : (type == Type::None ? -1 : (type == Type::Always ? -2 : number))) {}
-	int GetNumber() const { return value < 0 ? 0 : value; }
-	Type GetType() const { return value == 0 ? Type::Auto : (value == -1 ? Type::None : (value == -2 ? Type::Always : Type::Number)); }
-	bool operator==(Type type) const { return GetType() == type; }
-};
-
-enum class Visibility : uint8_t { Visible, Hidden };
-
-enum class FontStyle : uint8_t { Normal, Italic };
-enum class FontWeight : uint8_t { Normal, Bold };
-
-enum class TextAlign : uint8_t { Left, Right, Center, Justify };
-enum class TextDecoration : uint8_t { None, Underline, Overline, LineThrough };
-enum class TextTransform : uint8_t { None, Capitalize, Uppercase, Lowercase };
-enum class WhiteSpace : uint8_t { Normal, Pre, Nowrap, Prewrap, Preline };
-enum class WordBreak : uint8_t { Normal, BreakAll, BreakWord };
-
-enum class Drag : uint8_t { None, Drag, DragDrop, Block, Clone };
-enum class TabIndex : uint8_t { None, Auto };
-enum class Focus : uint8_t { None, Auto };
-enum class PointerEvents : uint8_t { None, Auto };
-
-using PerspectiveOrigin = LengthPercentage;
-using TransformOrigin = LengthPercentage;
-
-enum class OriginX : uint8_t { Left, Center, Right };
-enum class OriginY : uint8_t { Top, Center, Bottom };
-
-enum class AlignContent : uint8_t { FlexStart, FlexEnd, Center, SpaceBetween, SpaceAround, Stretch };
-enum class AlignItems : uint8_t { FlexStart, FlexEnd, Center, Baseline, Stretch };
-enum class AlignSelf : uint8_t { Auto, FlexStart, FlexEnd, Center, Baseline, Stretch };
-using FlexBasis = LengthPercentageAuto;
-enum class FlexDirection : uint8_t { Row, RowReverse, Column, ColumnReverse };
-enum class FlexWrap : uint8_t { Nowrap, Wrap, WrapReverse };
-enum class JustifyContent : uint8_t { FlexStart, FlexEnd, Center, SpaceBetween, SpaceAround };
-
-
-/* 
-	A computed value is a value resolved as far as possible :before: introducing layouting. See CSS specs for details of each property.
-
-	Note: Enums and default values must correspond to the keywords and defaults in `StyleSheetSpecification.cpp`.
-*/
-
-struct ComputedValues
-{
-	Margin margin_top, margin_right, margin_bottom, margin_left;
-	Padding padding_top, padding_right, padding_bottom, padding_left;
-	float border_top_width = 0, border_right_width = 0, border_bottom_width = 0, border_left_width = 0;
-	Colourb border_top_color{ 255, 255, 255 }, border_right_color{ 255, 255, 255 }, border_bottom_color{ 255, 255, 255 }, border_left_color{ 255, 255, 255 };
-	float border_top_left_radius = 0, border_top_right_radius = 0, border_bottom_right_radius = 0, border_bottom_left_radius = 0;
-
-	Display display = Display::Inline;
-	Position position = Position::Static;
-
-	Top top{ Top::Auto };
-	Right right{ Right::Auto };
-	Bottom bottom{ Bottom::Auto };
-	Left left{ Left::Auto };
-
-	Float float_ = Float::None;
-	Clear clear = Clear::None;
-
-	BoxSizing box_sizing = BoxSizing::ContentBox;
-
-	ZIndex z_index = { ZIndex::Auto };
-
-	Width width = { Width::Auto };
-	MinWidth min_width;
-	MaxWidth max_width{ MaxWidth::Length, -1.f };
-	Height height = { Height::Auto };
-	MinHeight min_height;
-	MaxHeight max_height{ MaxHeight::Length, -1.f };
-
-	LineHeight line_height;
-	VerticalAlign vertical_align;
-
-	Overflow overflow_x = Overflow::Visible, overflow_y = Overflow::Visible;
-	Clip clip;
-
-	Visibility visibility = Visibility::Visible;
-
-	Colourb background_color = Colourb(255, 255, 255, 0);
-	Colourb color = Colourb(255, 255, 255);
-	Colourb image_color = Colourb(255, 255, 255);
-	float opacity = 1;
-
-	String font_family;
-	FontStyle font_style = FontStyle::Normal;
-	FontWeight font_weight = FontWeight::Normal;
-	float font_size = 12.f;
-	// Font face used to render text and resolve ex properties. Does not represent a true property
-	// like most computed values, but placed here as it is used and inherited in a similar manner.
-	FontFaceHandle font_face_handle = 0;
-
-	TextAlign text_align = TextAlign::Left;
-	TextDecoration text_decoration = TextDecoration::None;
-	TextTransform text_transform = TextTransform::None;
-	WhiteSpace white_space = WhiteSpace::Normal;
-	WordBreak word_break = WordBreak::Normal;
-
-	LengthPercentage row_gap, column_gap;
-
-	String cursor;
-
-	Drag drag = Drag::None;
-	TabIndex tab_index = TabIndex::None;
-	Focus focus = Focus::Auto;
-	float scrollbar_margin = 0;
-	PointerEvents pointer_events = PointerEvents::Auto;
-
-	float perspective = 0;
-	PerspectiveOrigin perspective_origin_x = { PerspectiveOrigin::Percentage, 50.f };
-	PerspectiveOrigin perspective_origin_y = { PerspectiveOrigin::Percentage, 50.f };
-
-	TransformPtr transform;
-	TransformOrigin transform_origin_x = { TransformOrigin::Percentage, 50.f };
-	TransformOrigin transform_origin_y = { TransformOrigin::Percentage, 50.f };
-	float transform_origin_z = 0.0f;
-
-	TransitionList transition;
-	AnimationList animation;
+	/*
+	    A computed value is a value resolved as far as possible :before: introducing layouting. See CSS specs for details of each property.
 
-	bool has_decorator = false;
-	bool has_font_effect = false;
-
-	AlignContent align_content = AlignContent::Stretch;
-	AlignItems align_items = AlignItems::Stretch;
-	AlignSelf align_self = AlignSelf::Auto;
-	FlexDirection flex_direction = FlexDirection::Row;
-	FlexWrap flex_wrap = FlexWrap::Nowrap;
-	JustifyContent justify_content = JustifyContent::FlexStart;
-	FlexBasis flex_basis = { FlexBasis::Auto };
-	float flex_grow = 0.f;
-	float flex_shrink = 1.f;
-};
+	    Note: Enums and default values must correspond to the keywords and defaults in `StyleSheetSpecification.cpp`.
+	*/
 
-} // namespace Style
+	struct CommonValues {
+		CommonValues() :
+			display(Display::Inline), position(Position::Static), float_(Float::None), clear(Clear::None), overflow_x(Overflow::Visible),
+			overflow_y(Overflow::Visible), visibility(Visibility::Visible),
+
+			has_decorator(false), box_sizing(BoxSizing::ContentBox),
+
+			width_type(LengthPercentageAuto::Auto), height_type(LengthPercentageAuto::Auto),
+
+			margin_top_type(LengthPercentageAuto::Length), margin_right_type(LengthPercentageAuto::Length),
+			margin_bottom_type(LengthPercentageAuto::Length), margin_left_type(LengthPercentageAuto::Length),
+
+			padding_top_type(LengthPercentage::Length), padding_right_type(LengthPercentage::Length), padding_bottom_type(LengthPercentage::Length),
+			padding_left_type(LengthPercentage::Length),
+
+			top_type(LengthPercentageAuto::Auto), right_type(LengthPercentageAuto::Auto), bottom_type(LengthPercentageAuto::Auto),
+			left_type(LengthPercentageAuto::Auto), z_index_type(NumberAuto::Auto)
+		{}
+
+		Display display : 4;
+		Position position : 2;
+
+		Float float_ : 2;
+		Clear clear : 2;
+
+		Overflow overflow_x : 2, overflow_y : 2;
+		Visibility visibility : 1;
+
+		bool has_decorator : 1;
+		BoxSizing box_sizing : 1;
+
+		LengthPercentageAuto::Type width_type : 2, height_type : 2;
+
+		LengthPercentageAuto::Type margin_top_type : 2, margin_right_type : 2, margin_bottom_type : 2, margin_left_type : 2;
+		LengthPercentage::Type padding_top_type : 1, padding_right_type : 1, padding_bottom_type : 1, padding_left_type : 1;
+		LengthPercentageAuto::Type top_type : 2, right_type : 2, bottom_type : 2, left_type : 2;
+
+		NumberAuto::Type z_index_type : 1;
 
+		float width_value = 0;
+		float height_value = 0;
 
-// Resolves a computed LengthPercentage value to the base unit 'px'. 
+		float margin_top_value = 0;
+		float margin_right_value = 0;
+		float margin_bottom_value = 0;
+		float margin_left_value = 0;
+
+		float padding_top_value = 0;
+		float padding_right_value = 0;
+		float padding_bottom_value = 0;
+		float padding_left_value = 0;
+
+		float top_value = 0;
+		float right_value = 0;
+		float bottom_value = 0;
+		float left_value = 0;
+
+		float z_index_value = 0;
+
+		uint16_t border_top_width = 0, border_right_width = 0, border_bottom_width = 0, border_left_width = 0;
+
+		Colourb border_top_color{255, 255, 255}, border_right_color{255, 255, 255}, border_bottom_color{255, 255, 255},
+			border_left_color{255, 255, 255};
+
+		Colourb background_color = Colourb(255, 255, 255, 0);
+	};
+
+	struct InheritedValues {
+		InheritedValues() :
+			has_font_effect(false), font_style(FontStyle::Normal), font_weight(FontWeight::Normal), pointer_events(PointerEvents::Auto),
+			focus(Focus::Auto), text_align(TextAlign::Left), text_decoration(TextDecoration::None), text_transform(TextTransform::None),
+			white_space(WhiteSpace::Normal), word_break(WordBreak::Normal), line_height_inherit_type(LineHeight::Number)
+		{}
+
+		// Font face used to render text and resolve ex properties. Does not represent a true property
+		// like most computed values, but placed here as it is used and inherited in a similar manner.
+		FontFaceHandle font_face_handle = 0;
+
+		float font_size = 12.f;
+
+		float opacity = 1;
+		Colourb color = Colourb(255, 255, 255);
+
+		bool has_font_effect : 1;
+		FontStyle font_style : 1;
+		FontWeight font_weight : 1;
+
+		PointerEvents pointer_events : 1;
+		Focus focus : 1;
+
+		TextAlign text_align : 2;
+		TextDecoration text_decoration : 2;
+		TextTransform text_transform : 2;
+		WhiteSpace white_space : 3;
+		WordBreak word_break : 2;
+
+		LineHeight::InheritType line_height_inherit_type : 1;
+		float line_height = 12.f * 1.2f;
+		float line_height_inherit = 1.2f;
+	};
+
+	struct RareValues {
+		RareValues() :
+			min_width_type(LengthPercentage::Length), max_width_type(LengthPercentage::Length), min_height_type(LengthPercentage::Length),
+			max_height_type(LengthPercentage::Length),
+
+			perspective_origin_x_type(LengthPercentage::Percentage), perspective_origin_y_type(LengthPercentage::Percentage),
+			transform_origin_x_type(LengthPercentage::Percentage), transform_origin_y_type(LengthPercentage::Percentage),
+
+			flex_basis_type(LengthPercentageAuto::Auto), row_gap_type(LengthPercentage::Length), column_gap_type(LengthPercentage::Length),
+
+			vertical_align_type(VerticalAlign::Baseline), drag(Drag::None), tab_index(TabIndex::None)
+		{}
+
+		LengthPercentage::Type min_width_type : 1, max_width_type : 1;
+		LengthPercentage::Type min_height_type : 1, max_height_type : 1;
+
+		LengthPercentage::Type perspective_origin_x_type : 1, perspective_origin_y_type : 1;
+		LengthPercentage::Type transform_origin_x_type : 1, transform_origin_y_type : 1;
+
+		LengthPercentageAuto::Type flex_basis_type : 2;
+		LengthPercentage::Type row_gap_type : 1, column_gap_type : 1;
+
+		VerticalAlign::Type vertical_align_type : 4;
+		Drag drag : 3;
+		TabIndex tab_index : 1;
+
+		Clip clip;
+
+		float min_width = 0, max_width = -1;
+		float min_height = 0, max_height = -1;
+		float vertical_align_length = 0;
+
+		float perspective = 0;
+		float perspective_origin_x = 50.f;
+		float perspective_origin_y = 50.f;
+
+		float transform_origin_x = 50.f;
+		float transform_origin_y = 50.f;
+		float transform_origin_z = 0.0f;
+
+		float flex_basis = 0;
+		float row_gap = 0, column_gap = 0;
+
+		int16_t border_top_left_radius = 0, border_top_right_radius = 0, border_bottom_right_radius = 0, border_bottom_left_radius = 0;
+		Colourb image_color = Colourb(255, 255, 255);
+		float scrollbar_margin = 0.f;
+	};
+
+	class ComputedValues : NonCopyMoveable {
+	public:
+		ComputedValues(Element* element) : element(element) {}
+
+		// clang-format off
+		
+		// -- Common --
+		LengthPercentageAuto width()               const { return LengthPercentageAuto(common.width_type, common.width_value); }
+		LengthPercentageAuto height()              const { return LengthPercentageAuto(common.height_type, common.height_value); }
+		LengthPercentageAuto margin_top()          const { return LengthPercentageAuto(common.margin_top_type, common.margin_top_value); }
+		LengthPercentageAuto margin_right()        const { return LengthPercentageAuto(common.margin_right_type, common.margin_right_value); }
+		LengthPercentageAuto margin_bottom()       const { return LengthPercentageAuto(common.margin_bottom_type, common.margin_bottom_value); }
+		LengthPercentageAuto margin_left()         const { return LengthPercentageAuto(common.margin_left_type, common.margin_left_value); }
+		LengthPercentage     padding_top()         const { return LengthPercentage(common.padding_top_type, common.padding_top_value); }
+		LengthPercentage     padding_right()       const { return LengthPercentage(common.padding_right_type, common.padding_right_value); }
+		LengthPercentage     padding_bottom()      const { return LengthPercentage(common.padding_bottom_type, common.padding_bottom_value); }
+		LengthPercentage     padding_left()        const { return LengthPercentage(common.padding_left_type, common.padding_left_value); }
+		LengthPercentageAuto top()                 const { return LengthPercentageAuto(common.top_type, common.top_value); }
+		LengthPercentageAuto right()               const { return LengthPercentageAuto(common.right_type, common.right_value); }
+		LengthPercentageAuto bottom()              const { return LengthPercentageAuto(common.bottom_type, common.bottom_value); }
+		LengthPercentageAuto left()                const { return LengthPercentageAuto(common.left_type, common.left_value); }
+		NumberAuto           z_index()             const { return NumberAuto(common.z_index_type, common.z_index_value); }
+		float                border_top_width()    const { return (float)common.border_top_width; }
+		float                border_right_width()  const { return (float)common.border_right_width; }
+		float                border_bottom_width() const { return (float)common.border_bottom_width; }
+		float                border_left_width()   const { return (float)common.border_left_width; }
+		BoxSizing            box_sizing()          const { return common.box_sizing; }
+		Display              display()             const { return common.display; }
+		Position             position()            const { return common.position; }
+		Float                float_()              const { return common.float_; }
+		Clear                clear()               const { return common.clear; }
+		Overflow             overflow_x()          const { return common.overflow_x; }
+		Overflow             overflow_y()          const { return common.overflow_y; }
+		Visibility           visibility()          const { return common.visibility; }
+		Colourb              background_color()    const { return common.background_color; }
+		Colourb              border_top_color()    const { return common.border_top_color; }
+		Colourb              border_right_color()  const { return common.border_right_color; }
+		Colourb              border_bottom_color() const { return common.border_bottom_color; }
+		Colourb              border_left_color()   const { return common.border_left_color; }
+		bool                 has_decorator()       const { return common.has_decorator; }
+		
+		// -- Inherited --
+		String         font_family()      const;
+		String         cursor()           const;
+		FontFaceHandle font_face_handle() const { return inherited.font_face_handle; }
+		float          font_size()        const { return inherited.font_size; }
+		bool           has_font_effect()  const { return inherited.has_font_effect; }
+		FontStyle      font_style()       const { return inherited.font_style; }
+		FontWeight     font_weight()      const { return inherited.font_weight; }
+		PointerEvents  pointer_events()   const { return inherited.pointer_events; }
+		Focus          focus()            const { return inherited.focus; }
+		TextAlign      text_align()       const { return inherited.text_align; }
+		TextDecoration text_decoration()  const { return inherited.text_decoration; }
+		TextTransform  text_transform()   const { return inherited.text_transform; }
+		WhiteSpace     white_space()      const { return inherited.white_space; }
+		WordBreak      word_break()       const { return inherited.word_break; }
+		Colourb        color()            const { return inherited.color; }
+		float          opacity()          const { return inherited.opacity; }
+		LineHeight     line_height()      const { return LineHeight(inherited.line_height, inherited.line_height_inherit_type, inherited.line_height_inherit); }
+
+		// -- Rare --
+		MinWidth          min_width()                  const { return LengthPercentage(rare.min_width_type, rare.min_width); }
+		MaxWidth          max_width()                  const { return LengthPercentage(rare.max_width_type, rare.max_width); }
+		MinHeight         min_height()                 const { return LengthPercentage(rare.min_height_type, rare.min_height); }
+		MinHeight         max_height()                 const { return LengthPercentage(rare.max_height_type, rare.max_height); }
+		VerticalAlign     vertical_align()             const { return VerticalAlign(rare.vertical_align_type, rare.vertical_align_length); }
+		const             AnimationList* animation()   const;
+		const             TransitionList* transition() const;
+		float             perspective()                const { return rare.perspective; }
+		PerspectiveOrigin perspective_origin_x()       const { return LengthPercentage(rare.perspective_origin_x_type, rare.perspective_origin_x); }
+		PerspectiveOrigin perspective_origin_y()       const { return LengthPercentage(rare.perspective_origin_y_type, rare.perspective_origin_y); }
+		TransformPtr      transform()                  const { return GetLocalProperty(PropertyId::Transform, TransformPtr()); }
+		TransformOrigin   transform_origin_x()         const { return LengthPercentage(rare.transform_origin_x_type, rare.transform_origin_x); }
+		TransformOrigin   transform_origin_y()         const { return LengthPercentage(rare.transform_origin_y_type, rare.transform_origin_y); }
+		float             transform_origin_z()         const { return rare.transform_origin_z; }
+		AlignContent      align_content()              const { return GetLocalPropertyKeyword(PropertyId::AlignContent, AlignContent::Stretch); }
+		AlignItems        align_items()                const { return GetLocalPropertyKeyword(PropertyId::AlignItems, AlignItems::Stretch); }
+		AlignSelf         align_self()                 const { return GetLocalPropertyKeyword(PropertyId::AlignSelf, AlignSelf::Auto); }
+		FlexDirection     flex_direction()             const { return GetLocalPropertyKeyword(PropertyId::FlexDirection, FlexDirection::Row); }
+		FlexWrap          flex_wrap()                  const { return GetLocalPropertyKeyword(PropertyId::FlexWrap, FlexWrap::Nowrap); }
+		JustifyContent    justify_content()            const { return GetLocalPropertyKeyword(PropertyId::JustifyContent, JustifyContent::FlexStart); }
+		float             flex_grow()                  const { return GetLocalProperty(PropertyId::FlexGrow, 0.f); }
+		float             flex_shrink()                const { return GetLocalProperty(PropertyId::FlexShrink, 0.f); }
+		FlexBasis         flex_basis()                 const { return LengthPercentageAuto(rare.flex_basis_type, rare.flex_basis); }
+		float             border_top_left_radius()     const { return (float)rare.border_top_left_radius; }
+		float             border_top_right_radius()    const { return (float)rare.border_top_right_radius; }
+		float             border_bottom_right_radius() const { return (float)rare.border_bottom_right_radius; }
+		float             border_bottom_left_radius()  const { return (float)rare.border_bottom_left_radius; }
+		Clip              clip()                       const { return rare.clip; }
+		Drag              drag()                       const { return rare.drag; }
+		TabIndex          tab_index()                  const { return rare.tab_index; }
+		Colourb           image_color()                const { return rare.image_color; }
+		LengthPercentage  row_gap()                    const { return LengthPercentage(rare.row_gap_type, rare.row_gap); }
+		LengthPercentage  column_gap()                 const { return LengthPercentage(rare.column_gap_type, rare.column_gap); }
+		float             scrollbar_margin()           const { return rare.scrollbar_margin; }
+		
+		// -- Assignment --
+		// Common
+		void width              (LengthPercentageAuto value) { common.width_type          = value.type; common.width_value          = value.value; }
+		void height             (LengthPercentageAuto value) { common.height_type         = value.type; common.height_value         = value.value; }
+		void margin_top         (LengthPercentageAuto value) { common.margin_top_type     = value.type; common.margin_top_value     = value.value; }
+		void margin_right       (LengthPercentageAuto value) { common.margin_right_type   = value.type; common.margin_right_value   = value.value; }
+		void margin_bottom      (LengthPercentageAuto value) { common.margin_bottom_type  = value.type; common.margin_bottom_value  = value.value; }
+		void margin_left        (LengthPercentageAuto value) { common.margin_left_type    = value.type; common.margin_left_value    = value.value; }
+		void padding_top        (LengthPercentage value)     { common.padding_top_type    = value.type; common.padding_top_value    = value.value; }
+		void padding_right      (LengthPercentage value)     { common.padding_right_type  = value.type; common.padding_right_value  = value.value; }
+		void padding_bottom     (LengthPercentage value)     { common.padding_bottom_type = value.type; common.padding_bottom_value = value.value; }
+		void padding_left       (LengthPercentage value)     { common.padding_left_type   = value.type; common.padding_left_value   = value.value; }
+		void top                (LengthPercentageAuto value) { common.top_type            = value.type; common.top_value            = value.value; }
+		void right              (LengthPercentageAuto value) { common.right_type          = value.type; common.right_value          = value.value; }
+		void bottom             (LengthPercentageAuto value) { common.bottom_type         = value.type; common.bottom_value         = value.value; }
+		void left               (LengthPercentageAuto value) { common.left_type           = value.type; common.left_value           = value.value; }
+		void z_index            (NumberAuto value)           { common.z_index_type        = value.type; common.z_index_value        = value.value; }
+		void border_top_width   (int16_t value)              { common.border_top_width    = value; }
+		void border_right_width (int16_t value)              { common.border_right_width  = value; }
+		void border_bottom_width(int16_t value)              { common.border_bottom_width = value; }
+		void border_left_width  (int16_t value)              { common.border_left_width   = value; }
+		void box_sizing         (BoxSizing value)            { common.box_sizing          = value; }
+		void display            (Display value)              { common.display             = value; }
+		void position           (Position value)             { common.position            = value; }
+		void float_             (Float value)                { common.float_              = value; }
+		void clear              (Clear value)                { common.clear               = value; }
+		void overflow_x         (Overflow value)             { common.overflow_x          = value; }
+		void overflow_y         (Overflow value)             { common.overflow_y          = value; }
+		void visibility         (Visibility value)           { common.visibility          = value; }
+		void background_color   (Colourb value)              { common.background_color    = value; }
+		void border_top_color   (Colourb value)              { common.border_top_color    = value; }
+		void border_right_color (Colourb value)              { common.border_right_color  = value; }
+		void border_bottom_color(Colourb value)              { common.border_bottom_color = value; }
+		void border_left_color  (Colourb value)              { common.border_left_color   = value; }
+		void has_decorator      (bool value)                 { common.has_decorator       = value; }
+		// Inherited
+		void font_face_handle(FontFaceHandle value) { inherited.font_face_handle = value; }
+		void font_size       (float value)          { inherited.font_size        = value; }
+		void has_font_effect (bool value)           { inherited.has_font_effect  = value; }
+		void font_style      (FontStyle value)      { inherited.font_style       = value; }
+		void font_weight     (FontWeight value)     { inherited.font_weight      = value; }
+		void pointer_events  (PointerEvents value)  { inherited.pointer_events   = value; }
+		void focus           (Focus value)          { inherited.focus            = value; }
+		void text_align      (TextAlign value)      { inherited.text_align       = value; }
+		void text_decoration (TextDecoration value) { inherited.text_decoration  = value; }
+		void text_transform  (TextTransform value)  { inherited.text_transform   = value; }
+		void white_space     (WhiteSpace value)     { inherited.white_space      = value; }
+		void word_break      (WordBreak value)      { inherited.word_break       = value; }
+		void color           (Colourb value)        { inherited.color            = value; }
+		void opacity         (float value)          { inherited.opacity          = value; }
+		void line_height     (LineHeight value)     { inherited.line_height = value.value; inherited.line_height_inherit_type = value.inherit_type; inherited.line_height_inherit = value.inherit_value;  }
+		// Rare
+		void min_width                 (MinWidth value)          { rare.min_width_type             = value.type; rare.min_width                  = value.value; }
+		void max_width                 (MaxWidth value)          { rare.max_width_type             = value.type; rare.max_width                  = value.value; }
+		void min_height                (MinHeight value)         { rare.min_height_type            = value.type; rare.min_height                 = value.value; }
+		void max_height                (MaxHeight value)         { rare.max_height_type            = value.type; rare.max_height                 = value.value; }
+		void vertical_align            (VerticalAlign value)     { rare.vertical_align_type        = value.type; rare.vertical_align_length      = value.value; }
+		void perspective_origin_x      (PerspectiveOrigin value) { rare.perspective_origin_x_type  = value.type; rare.perspective_origin_x       = value.value; }
+		void perspective_origin_y      (PerspectiveOrigin value) { rare.perspective_origin_y_type  = value.type; rare.perspective_origin_y       = value.value; }
+		void transform_origin_x        (TransformOrigin value)   { rare.transform_origin_x_type    = value.type; rare.transform_origin_x         = value.value; }
+		void transform_origin_y        (TransformOrigin value)   { rare.transform_origin_y_type    = value.type; rare.transform_origin_y         = value.value; }
+		void row_gap                   (LengthPercentage value)  { rare.row_gap_type               = value.type; rare.row_gap                    = value.value; }
+		void column_gap                (LengthPercentage value)  { rare.column_gap_type            = value.type; rare.column_gap                 = value.value; }
+		void flex_basis                (FlexBasis value)         { rare.flex_basis_type            = value.type; rare.flex_basis                 = value.value; }
+		void transform_origin_z        (float value)             { rare.transform_origin_z         = value; }
+		void perspective               (float value)             { rare.perspective                = value; }
+		void border_top_left_radius    (float value)             { rare.border_top_left_radius     = (int16_t)value; }
+		void border_top_right_radius   (float value)             { rare.border_top_right_radius    = (int16_t)value; }
+		void border_bottom_right_radius(float value)             { rare.border_bottom_right_radius = (int16_t)value; }
+		void border_bottom_left_radius (float value)             { rare.border_bottom_left_radius  = (int16_t)value; }
+		void clip                      (Clip value)              { rare.clip                       = value; }
+		void drag                      (Drag value)              { rare.drag                       = value; }
+		void tab_index                 (TabIndex value)          { rare.tab_index                  = value; }
+		void image_color               (Colourb value)           { rare.image_color                = value; }
+		void scrollbar_margin          (float value)             { rare.scrollbar_margin           = value; }
+
+		// clang-format on
+
+		// -- Management --
+		void CopyNonInherited(const ComputedValues& other)
+		{
+			common = other.common;
+			rare = other.rare;
+		}
+		void CopyInherited(const ComputedValues& parent) { inherited = parent.inherited; }
+
+	private:
+		template <typename T>
+		inline T GetLocalPropertyKeyword(PropertyId id, T default_value) const
+		{
+			if (auto p = element->GetLocalProperty(id))
+				return static_cast<T>(p->Get<int>());
+			return default_value;
+		}
+		template <typename T>
+		inline T GetLocalProperty(PropertyId id, T default_value) const
+		{
+			if (auto p = element->GetLocalProperty(id))
+				return p->Get<T>();
+			return default_value;
+		}
+
+		Element* element = nullptr;
+
+		CommonValues common;
+		InheritedValues inherited;
+		RareValues rare;
+	};
+
+} // namespace Style
+
+// Resolves a computed LengthPercentage value to the base unit 'px'.
 // Percentages are scaled by the base_value.
 // Note: Auto must be manually handled during layout, here it returns zero.
 RMLUICORE_API float ResolveValue(Style::LengthPercentageAuto length, float base_value);
 RMLUICORE_API float ResolveValue(Style::LengthPercentage length, float base_value);
 
-
 using ComputedValues = Style::ComputedValues;
 
 } // namespace Rml

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

@@ -32,7 +32,7 @@
 #include "Header.h"
 #include "Types.h"
 #include "Event.h"
-#include "ComputedValues.h"
+#include "StyleTypes.h"
 
 namespace Rml {
 

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

@@ -29,16 +29,16 @@
 #ifndef RMLUI_CORE_ELEMENT_H
 #define RMLUI_CORE_ELEMENT_H
 
-#include "ScriptInterface.h"
-#include "Header.h"
 #include "Box.h"
-#include "ComputedValues.h"
 #include "Event.h"
+#include "Header.h"
 #include "ObserverPtr.h"
 #include "Property.h"
-#include "Types.h"
+#include "ScriptInterface.h"
+#include "StyleTypes.h"
 #include "Transform.h"
 #include "Tween.h"
+#include "Types.h"
 
 namespace Rml {
 

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

@@ -37,7 +37,7 @@ namespace Rml {
 class Box;
 class Context;
 class RenderInterface;
-namespace Style { struct ComputedValues; }
+namespace Style { class ComputedValues; }
 
 /**
 	Utility functions for dealing with elements.

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

@@ -29,9 +29,9 @@
 #define RMLUI_CORE_FONTENGINEINTERFACE_H
 
 #include "Header.h"
-#include "Types.h"
-#include "ComputedValues.h"
 #include "Geometry.h"
+#include "StyleTypes.h"
+#include "Types.h"
 
 namespace Rml {
 

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

@@ -32,7 +32,7 @@
 #include "Header.h"
 #include "Types.h"
 #include "Vertex.h"
-#include "ComputedValues.h"
+#include "StyleTypes.h"
 
 namespace Rml {
 

+ 152 - 0
Include/RmlUi/Core/StyleTypes.h

@@ -0,0 +1,152 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * 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 RMLUI_CORE_STYLETYPES_H
+#define RMLUI_CORE_STYLETYPES_H
+
+#include "Types.h"
+
+namespace Rml {
+namespace Style {
+
+	struct LengthPercentageAuto {
+		enum Type : uint8_t { Auto, Length, Percentage } type = Length;
+		float value = 0;
+		LengthPercentageAuto() {}
+		LengthPercentageAuto(Type type, float value = 0) : type(type), value(value) {}
+	};
+	struct LengthPercentage {
+		enum Type : uint8_t { Length, Percentage } type = Length;
+		float value = 0;
+		LengthPercentage() {}
+		LengthPercentage(Type type, float value = 0) : type(type), value(value) {}
+	};
+
+	struct NumberAuto {
+		enum Type : uint8_t { Auto, Number } type = Number;
+		float value = 0;
+		NumberAuto() {}
+		NumberAuto(Type type, float value = 0) : type(type), value(value) {}
+	};
+
+	using Margin = LengthPercentageAuto;
+	using Padding = LengthPercentage;
+
+	enum class Display : uint8_t { None, Block, Inline, InlineBlock, Flex, Table, TableRow, TableRowGroup, TableColumn, TableColumnGroup, TableCell };
+	enum class Position : uint8_t { Static, Relative, Absolute, Fixed };
+
+	using Top = LengthPercentageAuto;
+	using Right = LengthPercentageAuto;
+	using Bottom = LengthPercentageAuto;
+	using Left = LengthPercentageAuto;
+
+	enum class Float : uint8_t { None, Left, Right };
+	enum class Clear : uint8_t { None, Left, Right, Both };
+
+	enum class BoxSizing : uint8_t { ContentBox, BorderBox };
+
+	using ZIndex = NumberAuto;
+
+	using Width = LengthPercentageAuto;
+	using MinWidth = LengthPercentage;
+	using MaxWidth = LengthPercentage;
+
+	using Height = LengthPercentageAuto;
+	using MinHeight = LengthPercentage;
+	using MaxHeight = LengthPercentage;
+
+	struct LineHeight {
+		float value = 12.f * 1.2f; // The computed value (length)
+		enum InheritType : uint8_t { Number, Length } inherit_type = Number;
+		float inherit_value = 1.2f;
+		LineHeight() {}
+		LineHeight(float value, InheritType inherit_type, float inherit_value) :
+			value(value), inherit_type(inherit_type), inherit_value(inherit_value)
+		{}
+	};
+	struct VerticalAlign {
+		enum Type : uint8_t { Baseline, Middle, Sub, Super, TextTop, TextBottom, Top, Bottom, Length } type;
+		float value; // For length type
+		VerticalAlign(Type type = Baseline) : type(type), value(0) {}
+		VerticalAlign(float value) : type(Length), value(value) {}
+		VerticalAlign(Type type, float value) : type(type), value(value) {}
+	};
+
+	enum class Overflow : uint8_t { Visible, Hidden, Auto, Scroll };
+	struct Clip {
+	private:
+		// Here, 'value' is encoded with Auto <=> 0, None <=> -1, Always <=> -2. A value > 0 means the given number.
+		int8_t value = 0;
+
+	public:
+		// The Type enum must instead correspond to the keywords in StyleSheetSpec.
+		enum class Type : uint8_t { Auto, None, Always, Number };
+		Clip() {}
+		Clip(Type type, int8_t number = 0) : value(type == Type::Auto ? 0 : (type == Type::None ? -1 : (type == Type::Always ? -2 : number))) {}
+		int GetNumber() const { return value < 0 ? 0 : value; }
+		Type GetType() const { return value == 0 ? Type::Auto : (value == -1 ? Type::None : (value == -2 ? Type::Always : Type::Number)); }
+		bool operator==(Type type) const { return GetType() == type; }
+	};
+
+	enum class Visibility : uint8_t { Visible, Hidden };
+
+	enum class FontStyle : uint8_t { Normal, Italic };
+	enum class FontWeight : uint8_t { Normal, Bold };
+
+	enum class TextAlign : uint8_t { Left, Right, Center, Justify };
+	enum class TextDecoration : uint8_t { None, Underline, Overline, LineThrough };
+	enum class TextTransform : uint8_t { None, Capitalize, Uppercase, Lowercase };
+	enum class WhiteSpace : uint8_t { Normal, Pre, Nowrap, Prewrap, Preline };
+	enum class WordBreak : uint8_t { Normal, BreakAll, BreakWord };
+
+	enum class Drag : uint8_t { None, Drag, DragDrop, Block, Clone };
+	enum class TabIndex : uint8_t { None, Auto };
+	enum class Focus : uint8_t { None, Auto };
+	enum class PointerEvents : uint8_t { None, Auto };
+
+	using PerspectiveOrigin = LengthPercentage;
+	using TransformOrigin = LengthPercentage;
+
+	enum class OriginX : uint8_t { Left, Center, Right };
+	enum class OriginY : uint8_t { Top, Center, Bottom };
+
+	enum class AlignContent : uint8_t { FlexStart, FlexEnd, Center, SpaceBetween, SpaceAround, Stretch };
+	enum class AlignItems : uint8_t { FlexStart, FlexEnd, Center, Baseline, Stretch };
+	enum class AlignSelf : uint8_t { Auto, FlexStart, FlexEnd, Center, Baseline, Stretch };
+	using FlexBasis = LengthPercentageAuto;
+	enum class FlexDirection : uint8_t { Row, RowReverse, Column, ColumnReverse };
+	enum class FlexWrap : uint8_t { Nowrap, Wrap, WrapReverse };
+	enum class JustifyContent : uint8_t { FlexStart, FlexEnd, Center, SpaceBetween, SpaceAround };
+
+	class ComputedValues;
+
+} // namespace Style
+
+using ComputedValues = Style::ComputedValues;
+
+} // namespace Rml
+#endif

+ 16 - 26
Source/Core/ComputeProperty.cpp

@@ -26,36 +26,16 @@
  *
  */
 
-#include "../../Include/RmlUi/Core/Property.h"
 #include "ComputeProperty.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../Include/RmlUi/Core/Property.h"
 
 namespace Rml {
 
-const Style::ComputedValues DefaultComputedValues = Style::ComputedValues{};
+const Style::ComputedValues DefaultComputedValues{nullptr};
 
 static constexpr float PixelsPerInch = 96.0f;
 
-
-
-float ResolveValue(Style::LengthPercentageAuto length, float base_value)
-{
-	if (length.type == Style::LengthPercentageAuto::Length)
-		return length.value;
-	else if (length.type == Style::LengthPercentageAuto::Percentage)
-		return length.value * 0.01f * base_value;
-	return 0.0f;
-}
-
-float ResolveValue(Style::LengthPercentage length, float base_value)
-{
-	if (length.type == Style::LengthPercentage::Length)
-		return length.value;
-	else if (length.type == Style::LengthPercentage::Percentage)
-		return length.value * 0.01f * base_value;
-	return 0.0f;
-}
-
-
 float ComputeLength(const Property* property, float font_size, float document_font_size, float dp_ratio, Vector2f vp_dimensions)
 {
 	RMLUI_ASSERT(property);
@@ -194,16 +174,16 @@ float ComputeFontsize(const Property& property, const Style::ComputedValues& val
 		case Property::EM:
 			if (!parent_values)
 				return 0;
-			return property.value.Get< float >() * multiplier * parent_values->font_size;
+			return property.value.Get<float>() * multiplier * parent_values->font_size();
 
 		case Property::REM:
 			if (!document_values)
 				return 0;
 			// If the current element is a document, the rem unit is relative to the default size
 			if(&values == document_values)
-				return property.value.Get< float >() * DefaultComputedValues.font_size;
+				return property.value.Get<float>() * DefaultComputedValues.font_size();
 			// Otherwise it is relative to the document font size
-			return property.value.Get< float >() * document_values->font_size;
+			return property.value.Get<float>() * document_values->font_size();
 		default:
 			RMLUI_ERRORMSG("A relative unit must be percentage, em or rem.");
 		}
@@ -310,5 +290,15 @@ Style::LengthPercentage ComputeOrigin(const Property* property, float font_size,
 	return LengthPercentage(LengthPercentage::Length, ComputeLength(property, font_size, document_font_size, dp_ratio, vp_dimensions));
 }
 
+uint16_t ComputeBorderWidth(float computed_length)
+{
+	if (computed_length <= 0.f)
+		return 0;
+
+	if (computed_length <= 1.f)
+		return 1;
+	
+	return uint16_t(computed_length + 0.5f);
+}
 
 } // namespace Rml

+ 3 - 1
Source/Core/ComputeProperty.h

@@ -29,7 +29,7 @@
 #ifndef RMLUI_CORE_COMPUTEPROPERTY_H
 #define RMLUI_CORE_COMPUTEPROPERTY_H
 
-#include "../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../Include/RmlUi/Core/StyleTypes.h"
 
 namespace Rml {
 
@@ -58,6 +58,8 @@ Style::LengthPercentageAuto ComputeLengthPercentageAuto(const Property* property
 
 Style::LengthPercentage ComputeOrigin(const Property* property, float font_size, float document_font_size, float dp_ratio, Vector2f vp_dimensions);
 
+uint16_t ComputeBorderWidth(float computed_length);
+
 extern const Style::ComputedValues DefaultComputedValues;
 
 } // namespace Rml

+ 89 - 0
Source/Core/ComputedValues.cpp

@@ -0,0 +1,89 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * 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 "../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../Include/RmlUi/Core/Element.h"
+#include "ComputeProperty.h"
+
+namespace Rml {
+
+const AnimationList* Style::ComputedValues::animation() const
+{
+	if (auto p = element->GetLocalProperty(PropertyId::Animation))
+	{
+		if (p->unit == Property::ANIMATION)
+			return &(p->value.GetReference<AnimationList>());
+	}
+	return nullptr;
+}
+
+const TransitionList* Style::ComputedValues::transition() const
+{
+	if (auto p = element->GetLocalProperty(PropertyId::Transition))
+	{
+		if (p->unit == Property::TRANSITION)
+			return &(p->value.GetReference<TransitionList>());
+	}
+	return nullptr;
+}
+
+String Style::ComputedValues::font_family() const
+{
+	if (auto p = element->GetProperty(PropertyId::FontFamily))
+		return ComputeFontFamily(p->Get<String>());
+
+	return String();
+}
+
+String Style::ComputedValues::cursor() const
+{
+	if (auto p = element->GetProperty(PropertyId::Cursor))
+		return p->Get<String>();
+
+	return String();
+}
+
+float ResolveValue(Style::LengthPercentageAuto length, float base_value)
+{
+	if (length.type == Style::LengthPercentageAuto::Length)
+		return length.value;
+	else if (length.type == Style::LengthPercentageAuto::Percentage)
+		return length.value * 0.01f * base_value;
+	return 0.0f;
+}
+
+float ResolveValue(Style::LengthPercentage length, float base_value)
+{
+	if (length.type == Style::LengthPercentage::Length)
+		return length.value;
+	else if (length.type == Style::LengthPercentage::Percentage)
+		return length.value * 0.01f * base_value;
+	return 0.0f;
+}
+
+} // namespace Rml

+ 9 - 8
Source/Core/Context.cpp

@@ -28,6 +28,7 @@
 
 #include "../../Include/RmlUi/Core/Context.h"
 #include "../../Include/RmlUi/Core/ContextInstancer.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Core.h"
 #include "../../Include/RmlUi/Core/DataModelHandle.h"
 #include "../../Include/RmlUi/Core/ElementDocument.h"
@@ -630,10 +631,10 @@ bool Context::ProcessMouseMove(int x, int y, int key_modifier_state)
 static Element* FindFocusElement(Element* element)
 {
 	ElementDocument* owner_document = element->GetOwnerDocument();
-	if (!owner_document || owner_document->GetComputedValues().focus == Style::Focus::None)
+	if (!owner_document || owner_document->GetComputedValues().focus() == Style::Focus::None)
 		return nullptr;
 	
-	while (element && element->GetComputedValues().focus == Style::Focus::None)
+	while (element && element->GetComputedValues().focus() == Style::Focus::None)
 	{
 		element = element->GetParentNode();
 	}
@@ -709,7 +710,7 @@ bool Context::ProcessMouseButtonDown(int button_index, int key_modifier_state)
 			drag = hover;
 			while (drag)
 			{
-				Style::Drag drag_style = drag->GetComputedValues().drag;
+				Style::Drag drag_style = drag->GetComputedValues().drag();
 				switch (drag_style)
 				{
 				case Style::Drag::None:		drag = drag->GetParentNode(); continue;
@@ -1009,7 +1010,7 @@ bool Context::OnFocusChange(Element* new_focus)
 	ElementDocument* document = focus->GetOwnerDocument();
 	if (document != nullptr)
 	{
-		Style::ZIndex z_index_property = document->GetComputedValues().z_index;
+		Style::ZIndex z_index_property = document->GetComputedValues().z_index();
 		if (z_index_property.type == Style::ZIndex::Auto)
 			document->PullToFront();
 	}
@@ -1056,7 +1057,7 @@ void Context::UpdateHoverChain(const Dictionary& parameters, const Dictionary& d
 				drag->DispatchEvent(EventId::Dragstart, drag_start_parameters);
 				drag_started = true;
 
-				if (drag->GetComputedValues().drag == Style::Drag::Clone)
+				if (drag->GetComputedValues().drag() == Style::Drag::Clone)
 				{
 					// Clone the element and attach it to the mouse cursor.
 					CreateDragClone(drag);
@@ -1074,9 +1075,9 @@ void Context::UpdateHoverChain(const Dictionary& parameters, const Dictionary& d
 		String new_cursor_name;
 
 		if(drag)
-			new_cursor_name = drag->GetComputedValues().cursor;
+			new_cursor_name = drag->GetComputedValues().cursor();
 		else if (hover)
-			new_cursor_name = hover->GetComputedValues().cursor;
+			new_cursor_name = hover->GetComputedValues().cursor();
 
 		if(new_cursor_name != cursor_name)
 		{
@@ -1183,7 +1184,7 @@ Element* Context::GetElementAtPoint(Vector2f point, const Element* ignore_elemen
 	}
 
 	// Ignore elements whose pointer events are disabled.
-	if (element->GetComputedValues().pointer_events == Style::PointerEvents::None)
+	if (element->GetComputedValues().pointer_events() == Style::PointerEvents::None)
 		return nullptr;
 
 	// Projection may fail if we have a singular transformation matrix.

+ 6 - 5
Source/Core/DecoratorGradient.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "DecoratorGradient.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../Include/RmlUi/Core/Geometry.h"
@@ -70,13 +71,13 @@ DecoratorDataHandle DecoratorGradient::GenerateElementData(Element* element) con
 	const Box& box = element->GetBox();
 
 	const ComputedValues& computed = element->GetComputedValues();
-	const float opacity = computed.opacity;
+	const float opacity = computed.opacity();
 
 	const Vector4f border_radius{
-		computed.border_top_left_radius,
-		computed.border_top_right_radius,
-		computed.border_bottom_right_radius,
-		computed.border_bottom_left_radius,
+		computed.border_top_left_radius(),
+		computed.border_top_right_radius(),
+		computed.border_bottom_right_radius(),
+		computed.border_bottom_left_radius(),
 	};
 	GeometryUtilities::GenerateBackgroundBorder(geometry, element->GetBox(), Vector2f(0), border_radius, Colourb());
 

+ 3 - 2
Source/Core/DecoratorNinePatch.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "DecoratorNinePatch.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/Geometry.h"
 #include "../../Include/RmlUi/Core/ElementUtilities.h"
@@ -69,8 +70,8 @@ DecoratorDataHandle DecoratorNinePatch::GenerateElementData(Element* element) co
 
 	const Vector2f surface_dimensions = element->GetBox().GetSize(Box::PADDING).Round();
 
-	const float opacity = computed.opacity;
-	Colourb quad_colour = computed.image_color;
+	const float opacity = computed.opacity();
+	Colourb quad_colour = computed.image_color();
 
 	quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha);
 

+ 2 - 2
Source/Core/DecoratorTiled.cpp

@@ -118,8 +118,8 @@ void DecoratorTiled::Tile::GenerateGeometry(Vector< Vertex >& vertices, Vector<
 	RenderInterface* render_interface = element->GetRenderInterface();
 	const auto& computed = element->GetComputedValues();
 
-	float opacity = computed.opacity;
-	Colourb quad_colour = computed.image_color;
+	float opacity = computed.opacity();
+	Colourb quad_colour = computed.image_color();
 
     // Apply opacity
     quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha);

+ 97 - 77
Source/Core/Element.cpp

@@ -73,7 +73,7 @@ static constexpr int ChildNotifyLevels = 2;
 // Meta objects for element collected in a single struct to reduce memory allocations
 struct ElementMeta
 {
-	ElementMeta(Element* el) : event_dispatcher(el), style(el), background_border(el), decoration(el), scroll(el) {}
+	ElementMeta(Element* el) : event_dispatcher(el), style(el), background_border(el), decoration(el), scroll(el), computed_values(el) {}
 	SmallUnorderedMap<EventId, EventListener*> attribute_event_listeners;
 	EventDispatcher event_dispatcher;
 	ElementStyle style;
@@ -555,7 +555,7 @@ float Element::GetZIndex() const
 // Returns the element's font face handle.
 FontFaceHandle Element::GetFontFaceHandle() const
 {
-	return meta->computed_values.font_face_handle;
+	return meta->computed_values.font_face_handle();
 }
 
 // Sets a local property override on the element.
@@ -670,22 +670,22 @@ Vector2f Element::GetContainingBlock()
 
 Style::Position Element::GetPosition()
 {
-	return meta->computed_values.position;
+	return meta->computed_values.position();
 }
 
 Style::Float Element::GetFloat()
 {
-	return meta->computed_values.float_;
+	return meta->computed_values.float_();
 }
 
 Style::Display Element::GetDisplay()
 {
-	return meta->computed_values.display;
+	return meta->computed_values.display();
 }
 
 float Element::GetLineHeight()
 {
-	return meta->computed_values.line_height.value;
+	return meta->computed_values.line_height().value;
 }
 
 // Returns this element's TransformState
@@ -1145,7 +1145,7 @@ void Element::SetInnerRML(const String& rml)
 bool Element::Focus()
 {
 	// Are we allowed focus?
-	Style::Focus focus_property = meta->computed_values.focus;
+	Style::Focus focus_property = meta->computed_values.focus();
 	if (focus_property == Style::Focus::None)
 		return false;
 
@@ -1261,8 +1261,8 @@ void Element::ScrollIntoView(bool align_with_top)
 	{
 		using Style::Overflow;
 		const ComputedValues& computed = scroll_parent->GetComputedValues();
-		const bool scrollable_box_x = (computed.overflow_x != Overflow::Visible && computed.overflow_x != Overflow::Hidden);
-		const bool scrollable_box_y = (computed.overflow_y != Overflow::Visible && computed.overflow_y != Overflow::Hidden);
+		const bool scrollable_box_x = (computed.overflow_x() != Overflow::Visible && computed.overflow_x() != Overflow::Hidden);
+		const bool scrollable_box_y = (computed.overflow_y() != Overflow::Visible && computed.overflow_y() != Overflow::Hidden);
 
 		const Vector2f parent_scroll_size = { scroll_parent->GetScrollWidth(), scroll_parent->GetScrollHeight() };
 		const Vector2f parent_client_size = { scroll_parent->GetClientWidth(), scroll_parent->GetClientHeight() };
@@ -1663,8 +1663,8 @@ void Element::OnAttributeChange(const ElementAttributes& changed_attributes)
 		{
 			meta->style.SetClassNames(value.Get<String>());
 		}
-		else if (((attribute == "colspan" || attribute == "rowspan") && meta->computed_values.display == Style::Display::TableCell)
-			|| (attribute == "span" && (meta->computed_values.display == Style::Display::TableColumn || meta->computed_values.display == Style::Display::TableColumnGroup)))
+		else if (((attribute == "colspan" || attribute == "rowspan") && meta->computed_values.display() == Style::Display::TableCell)
+			|| (attribute == "span" && (meta->computed_values.display() == Style::Display::TableColumn || meta->computed_values.display() == Style::Display::TableColumnGroup)))
 		{
 			DirtyLayout();
 		}
@@ -1740,7 +1740,8 @@ void Element::OnPropertyChange(const PropertyIdSet& changed_properties)
 	if (changed_properties.Contains(PropertyId::Visibility) ||
 		changed_properties.Contains(PropertyId::Display))
 	{
-		bool new_visibility = (meta->computed_values.display != Style::Display::None && meta->computed_values.visibility == Style::Visibility::Visible);
+		bool new_visibility =
+			(meta->computed_values.display() != Style::Display::None && meta->computed_values.visibility() == Style::Visibility::Visible);
 			
 		if (visible != new_visibility)
 		{
@@ -1776,7 +1777,7 @@ void Element::OnPropertyChange(const PropertyIdSet& changed_properties)
 	// Update the z-index.
 	if (changed_properties.Contains(PropertyId::ZIndex))
 	{
-		Style::ZIndex z_index_property = meta->computed_values.z_index;
+		Style::ZIndex z_index_property = meta->computed_values.z_index();
 
 		if (z_index_property.type == Style::ZIndex::Auto)
 		{
@@ -1929,7 +1930,7 @@ void Element::ProcessDefaultAction(Event& event)
 	{
 		if (GetScrollHeight() > GetClientHeight())
 		{
-			Style::Overflow overflow_property = meta->computed_values.overflow_y;
+			Style::Overflow overflow_property = meta->computed_values.overflow_y();
 			if (overflow_property == Style::Overflow::Auto ||
 				overflow_property == Style::Overflow::Scroll)
 			{
@@ -1944,7 +1945,7 @@ void Element::ProcessDefaultAction(Event& event)
 					(wheel_delta > 0 && GetScrollHeight() > GetScrollTop() + GetClientHeight()))
 				{
 					// Defined as three times the default line-height, multiplied by the dp ratio.
-					float default_scroll_length = 3.f * DefaultComputedValues.line_height.value;
+					float default_scroll_length = 3.f * DefaultComputedValues.line_height().value;
 					if (const Context* context = GetContext())
 						default_scroll_length *= context->GetDensityIndependentPixelRatio();
 
@@ -2135,7 +2136,7 @@ void Element::UpdateOffset()
 {
 	using namespace Style;
 	const auto& computed = meta->computed_values;
-	Position position_property = computed.position;
+	Position position_property = computed.position();
 
 	if (position_property == Position::Absolute ||
 		position_property == Position::Fixed)
@@ -2146,24 +2147,36 @@ void Element::UpdateOffset()
 			Vector2f containing_block = parent_box.GetSize(Box::PADDING);
 
 			// If the element is anchored left, then the position is offset by that resolved value.
-			if (computed.left.type != Left::Auto)
-				relative_offset_base.x = parent_box.GetEdge(Box::BORDER, Box::LEFT) + (ResolveValue(computed.left, containing_block.x) + GetBox().GetEdge(Box::MARGIN, Box::LEFT));
+			if (computed.left().type != Left::Auto)
+				relative_offset_base.x = parent_box.GetEdge(Box::BORDER, Box::LEFT) +
+					(ResolveValue(computed.left(), containing_block.x) + GetBox().GetEdge(Box::MARGIN, Box::LEFT));
 
 			// If the element is anchored right, then the position is set first so the element's right-most edge
 			// (including margins) will render up against the containing box's right-most content edge, and then
 			// offset by the resolved value.
-			else if (computed.right.type != Right::Auto)
-				relative_offset_base.x = containing_block.x + parent_box.GetEdge(Box::BORDER, Box::LEFT) - (ResolveValue(computed.right, containing_block.x) + GetBox().GetSize(Box::BORDER).x + GetBox().GetEdge(Box::MARGIN, Box::RIGHT));
+			else if (computed.right().type != Right::Auto)
+			{
+				relative_offset_base.x = containing_block.x + parent_box.GetEdge(Box::BORDER, Box::LEFT) -
+					(ResolveValue(computed.right(), containing_block.x) + GetBox().GetSize(Box::BORDER).x +
+						GetBox().GetEdge(Box::MARGIN, Box::RIGHT));
+			}
 
 			// If the element is anchored top, then the position is offset by that resolved value.
-			if (computed.top.type != Top::Auto)
-				relative_offset_base.y = parent_box.GetEdge(Box::BORDER, Box::TOP) + (ResolveValue(computed.top, containing_block.y) + GetBox().GetEdge(Box::MARGIN, Box::TOP));
+			if (computed.top().type != Top::Auto)
+			{
+				relative_offset_base.y = parent_box.GetEdge(Box::BORDER, Box::TOP) +
+					(ResolveValue(computed.top(), containing_block.y) + GetBox().GetEdge(Box::MARGIN, Box::TOP));
+			}
 
 			// If the element is anchored bottom, then the position is set first so the element's right-most edge
 			// (including margins) will render up against the containing box's right-most content edge, and then
 			// offset by the resolved value.
-			else if (computed.bottom.type != Bottom::Auto)
-				relative_offset_base.y = containing_block.y + parent_box.GetEdge(Box::BORDER, Box::TOP) - (ResolveValue(computed.bottom, containing_block.y) + GetBox().GetSize(Box::BORDER).y + GetBox().GetEdge(Box::MARGIN, Box::BOTTOM));
+			else if (computed.bottom().type != Bottom::Auto)
+			{
+				relative_offset_base.y = containing_block.y + parent_box.GetEdge(Box::BORDER, Box::TOP) -
+					(ResolveValue(computed.bottom(), containing_block.y) + GetBox().GetSize(Box::BORDER).y +
+						GetBox().GetEdge(Box::MARGIN, Box::BOTTOM));
+			}
 		}
 	}
 	else if (position_property == Position::Relative)
@@ -2173,17 +2186,17 @@ void Element::UpdateOffset()
 			const Box& parent_box = offset_parent->GetBox();
 			Vector2f containing_block = parent_box.GetSize();
 
-			if (computed.left.type != Left::Auto)
-				relative_offset_position.x = ResolveValue(computed.left, containing_block.x);
-			else if (computed.right.type != Right::Auto)
-				relative_offset_position.x = -1 * ResolveValue(computed.right, containing_block.x);
+			if (computed.left().type != Left::Auto)
+				relative_offset_position.x = ResolveValue(computed.left(), containing_block.x);
+			else if (computed.right().type != Right::Auto)
+				relative_offset_position.x = -1 * ResolveValue(computed.right(), containing_block.x);
 			else
 				relative_offset_position.x = 0;
 
-			if (computed.top.type != Top::Auto)
-				relative_offset_position.y = ResolveValue(computed.top, containing_block.y);
-			else if (computed.bottom.type != Bottom::Auto)
-				relative_offset_position.y = -1 * ResolveValue(computed.bottom, containing_block.y);
+			if (computed.top().type != Top::Auto)
+				relative_offset_position.y = ResolveValue(computed.top(), containing_block.y);
+			else if (computed.bottom().type != Bottom::Auto)
+				relative_offset_position.y = -1 * ResolveValue(computed.bottom(), containing_block.y);
 			else
 				relative_offset_position.y = 0;
 		}
@@ -2506,14 +2519,14 @@ void Element::HandleTransitionProperty()
 		dirty_transition = false;
 
 		// Remove all transitions that are no longer in our local list
-		const TransitionList& keep_transitions = GetComputedValues().transition;
+		const TransitionList* keep_transitions = GetComputedValues().transition();
 
-		if (keep_transitions.all)
+		if (keep_transitions && keep_transitions->all)
 			return;
 
 		auto it_remove = animations.end();
 
-		if (keep_transitions.none)
+		if (!keep_transitions || keep_transitions->none)
 		{
 			// All transitions should be removed, but only touch the animations that originate from the 'transition' property.
 			// Move all animations to be erased in a valid state at the end of the list, and erase later.
@@ -2523,8 +2536,10 @@ void Element::HandleTransitionProperty()
 		}
 		else
 		{
+			RMLUI_ASSERT(keep_transitions);
+
 			// Only remove the transitions that are not in our keep list.
-			const auto& keep_transitions_list = keep_transitions.transitions;
+			const auto& keep_transitions_list = keep_transitions->transitions;
 
 			it_remove = std::partition(animations.begin(), animations.end(),
 				[&keep_transitions_list](const ElementAnimation& animation) -> bool {
@@ -2555,8 +2570,8 @@ void Element::HandleAnimationProperty()
 	{
 		dirty_animation = false;
 
-		const AnimationList& animation_list = meta->computed_values.animation;
-		bool element_has_animations = (!animation_list.empty() || !animations.empty());
+		const AnimationList* animation_list = meta->computed_values.animation();
+		bool element_has_animations = ((animation_list && !animation_list->empty()) || !animations.empty());
 		const StyleSheet* stylesheet = nullptr;
 
 		if (element_has_animations)
@@ -2579,34 +2594,39 @@ void Element::HandleAnimationProperty()
 			}
 
 			// Start animations
-			for (const auto& animation : animation_list)
+			if (animation_list)
 			{
-				const Keyframes* keyframes_ptr = stylesheet->GetKeyframes(animation.name);
-				if (keyframes_ptr && keyframes_ptr->blocks.size() >= 1 && !animation.paused)
+				for (const auto& animation : *animation_list)
 				{
-					auto& property_ids = keyframes_ptr->property_ids;
-					auto& blocks = keyframes_ptr->blocks;
+					const Keyframes* keyframes_ptr = stylesheet->GetKeyframes(animation.name);
+					if (keyframes_ptr && keyframes_ptr->blocks.size() >= 1 && !animation.paused)
+					{
+						auto& property_ids = keyframes_ptr->property_ids;
+						auto& blocks = keyframes_ptr->blocks;
 
-					bool has_from_key = (blocks[0].normalized_time == 0);
-					bool has_to_key = (blocks.back().normalized_time == 1);
+						bool has_from_key = (blocks[0].normalized_time == 0);
+						bool has_to_key = (blocks.back().normalized_time == 1);
 
-					// If the first key defines initial conditions for a given property, use those values, else, use this element's current values.
-					for (PropertyId id : property_ids)
-						StartAnimation(id, (has_from_key ? blocks[0].properties.GetProperty(id) : nullptr), animation.num_iterations, animation.alternate, animation.delay, true);
+						// If the first key defines initial conditions for a given property, use those values, else, use this element's current
+						// values.
+						for (PropertyId id : property_ids)
+							StartAnimation(id, (has_from_key ? blocks[0].properties.GetProperty(id) : nullptr), animation.num_iterations,
+								animation.alternate, animation.delay, true);
 
-					// Add middle keys: Need to skip the first and last keys if they set the initial and end conditions, respectively.
-					for (int i = (has_from_key ? 1 : 0); i < (int)blocks.size() + (has_to_key ? -1 : 0); i++)
-					{
-						// Add properties of current key to animation
-						float time = blocks[i].normalized_time * animation.duration;
-						for (auto& property : blocks[i].properties.GetProperties())
-							AddAnimationKeyTime(property.first, &property.second, time, animation.tween);
-					}
+						// Add middle keys: Need to skip the first and last keys if they set the initial and end conditions, respectively.
+						for (int i = (has_from_key ? 1 : 0); i < (int)blocks.size() + (has_to_key ? -1 : 0); i++)
+						{
+							// Add properties of current key to animation
+							float time = blocks[i].normalized_time * animation.duration;
+							for (auto& property : blocks[i].properties.GetProperties())
+								AddAnimationKeyTime(property.first, &property.second, time, animation.tween);
+						}
 
-					// If the last key defines end conditions for a given property, use those values, else, use this element's current values.
-					float time = animation.duration;
-					for (PropertyId id : property_ids)
-						AddAnimationKeyTime(id, (has_to_key ? blocks.back().properties.GetProperty(id) : nullptr), time, animation.tween);
+						// If the last key defines end conditions for a given property, use those values, else, use this element's current values.
+						float time = animation.duration;
+						for (PropertyId id : property_ids)
+							AddAnimationKeyTime(id, (has_to_key ? blocks.back().properties.GetProperty(id) : nullptr), time, animation.tween);
+					}
 				}
 			}
 		}
@@ -2683,7 +2703,7 @@ void Element::UpdateTransformState()
 		// and let the children's transform update merge it with their transform.
 		bool had_perspective = (transform_state && transform_state->GetLocalPerspective());
 
-		float distance = computed.perspective;
+		float distance = computed.perspective();
 		Vector2f vanish = Vector2f(pos.x + size.x * 0.5f, pos.y + size.y * 0.5f);
 		bool have_perspective = false;
 
@@ -2692,15 +2712,15 @@ void Element::UpdateTransformState()
 			have_perspective = true;
 
 			// Compute the vanishing point from the perspective origin
-			if (computed.perspective_origin_x.type == Style::PerspectiveOrigin::Percentage)
-				vanish.x = pos.x + computed.perspective_origin_x.value * 0.01f * size.x;
+			if (computed.perspective_origin_x().type == Style::PerspectiveOrigin::Percentage)
+				vanish.x = pos.x + computed.perspective_origin_x().value * 0.01f * size.x;
 			else
-				vanish.x = pos.x + computed.perspective_origin_x.value;
+				vanish.x = pos.x + computed.perspective_origin_x().value;
 
-			if (computed.perspective_origin_y.type == Style::PerspectiveOrigin::Percentage)
-				vanish.y = pos.y + computed.perspective_origin_y.value * 0.01f * size.y;
+			if (computed.perspective_origin_y().type == Style::PerspectiveOrigin::Percentage)
+				vanish.y = pos.y + computed.perspective_origin_y().value * 0.01f * size.y;
 			else
-				vanish.y = pos.y + computed.perspective_origin_y.value;
+				vanish.y = pos.y + computed.perspective_origin_y().value;
 		}
 
 		if (have_perspective)
@@ -2736,13 +2756,13 @@ void Element::UpdateTransformState()
 		bool have_transform = false;
 		Matrix4f transform = Matrix4f::Identity();
 
-		if (computed.transform)
+		if (TransformPtr transform_ptr = computed.transform())
 		{
 			// First find the current element's transform
-			const int n = computed.transform->GetNumPrimitives();
+			const int n = transform_ptr->GetNumPrimitives();
 			for (int i = 0; i < n; ++i)
 			{
-				const TransformPrimitive& primitive = computed.transform->GetPrimitive(i);
+				const TransformPrimitive& primitive = transform_ptr->GetPrimitive(i);
 				Matrix4f matrix = TransformUtilities::ResolveTransform(primitive, *this);
 				transform *= matrix;
 				have_transform = true;
@@ -2753,17 +2773,17 @@ void Element::UpdateTransformState()
 				// Compute the transform origin
 				Vector3f transform_origin(pos.x + size.x * 0.5f, pos.y + size.y * 0.5f, 0);
 
-				if (computed.transform_origin_x.type == Style::TransformOrigin::Percentage)
-					transform_origin.x = pos.x + computed.transform_origin_x.value * size.x * 0.01f;
+				if (computed.transform_origin_x().type == Style::TransformOrigin::Percentage)
+					transform_origin.x = pos.x + computed.transform_origin_x().value * size.x * 0.01f;
 				else
-					transform_origin.x = pos.x + computed.transform_origin_x.value;
+					transform_origin.x = pos.x + computed.transform_origin_x().value;
 
-				if (computed.transform_origin_y.type == Style::TransformOrigin::Percentage)
-					transform_origin.y = pos.y + computed.transform_origin_y.value * size.y * 0.01f;
+				if (computed.transform_origin_y().type == Style::TransformOrigin::Percentage)
+					transform_origin.y = pos.y + computed.transform_origin_y().value * size.y * 0.01f;
 				else
-					transform_origin.y = pos.y + computed.transform_origin_y.value;
+					transform_origin.y = pos.y + computed.transform_origin_y().value;
 
-				transform_origin.z = computed.transform_origin_z;
+				transform_origin.z = computed.transform_origin_z();
 
 				// Make the transformation apply relative to the transform origin
 				transform = Matrix4f::Translate(transform_origin) * transform * Matrix4f::Translate(-transform_origin);

+ 8 - 12
Source/Core/ElementBackgroundBorder.cpp

@@ -66,16 +66,16 @@ void ElementBackgroundBorder::GenerateGeometry(Element* element)
 {
 	const ComputedValues& computed = element->GetComputedValues();
 
-	Colourb background_color = computed.background_color;
+	Colourb background_color = computed.background_color();
 	Colourb border_colors[4] = {
-		computed.border_top_color,
-		computed.border_right_color,
-		computed.border_bottom_color,
-		computed.border_left_color,
+		computed.border_top_color(),
+		computed.border_right_color(),
+		computed.border_bottom_color(),
+		computed.border_left_color(),
 	};
 	
 	// Apply opacity
-	const float opacity = computed.opacity;
+	const float opacity = computed.opacity();
 	background_color.alpha = (byte)(opacity * (float)background_color.alpha);
 
 	if (opacity < 1)
@@ -87,12 +87,8 @@ void ElementBackgroundBorder::GenerateGeometry(Element* element)
 	geometry.GetVertices().clear();
 	geometry.GetIndices().clear();
 
-	const Vector4f radii(
-		computed.border_top_left_radius,
-		computed.border_top_right_radius,
-		computed.border_bottom_right_radius,
-		computed.border_bottom_left_radius
-	);
+	const Vector4f radii(computed.border_top_left_radius(), computed.border_top_right_radius(), computed.border_bottom_right_radius(),
+		computed.border_bottom_left_radius());
 
 	for (int i = 0; i < element->GetNumBoxes(); i++)
 	{

+ 2 - 1
Source/Core/ElementDecoration.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "ElementDecoration.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Decorator.h"
 #include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/ElementDocument.h"
@@ -60,7 +61,7 @@ bool ElementDecoration::ReloadDecorators()
 	RMLUI_ZoneScopedC(0xB22222);
 	ReleaseDecorators();
 
-	if (!element->GetComputedValues().has_decorator)
+	if (!element->GetComputedValues().has_decorator())
 		return true;
 
 	const Property* property = element->GetLocalProperty(PropertyId::Decorator);

+ 11 - 11
Source/Core/ElementDocument.cpp

@@ -458,17 +458,17 @@ void ElementDocument::UpdatePosition()
 
 		auto& computed = GetComputedValues();
 
-		if (computed.left.type != Style::Left::Auto)
-			position.x = ResolveValue(computed.left, containing_block.x);
-		else if (computed.right.type != Style::Right::Auto)
-			position.x = (containing_block.x - GetBox().GetSize(Box::MARGIN).x) - ResolveValue(computed.right, containing_block.x);
+		if (computed.left().type != Style::Left::Auto)
+			position.x = ResolveValue(computed.left(), containing_block.x);
+		else if (computed.right().type != Style::Right::Auto)
+			position.x = (containing_block.x - GetBox().GetSize(Box::MARGIN).x) - ResolveValue(computed.right(), containing_block.x);
 		else
 			position.x = GetBox().GetEdge(Box::MARGIN, Box::LEFT);
 
-		if (computed.top.type != Style::Top::Auto)
-			position.y = ResolveValue(computed.top, containing_block.y);
-		else if (computed.bottom.type != Style::Bottom::Auto)
-			position.y = (containing_block.y - GetBox().GetSize(Box::MARGIN).y) - ResolveValue(computed.bottom, containing_block.y);
+		if (computed.top().type != Style::Top::Auto)
+			position.y = ResolveValue(computed.top(), containing_block.y);
+		else if (computed.bottom().type != Style::Bottom::Auto)
+			position.y = (containing_block.y - GetBox().GetSize(Box::MARGIN).y) - ResolveValue(computed.bottom(), containing_block.y);
 		else
 			position.y = GetBox().GetEdge(Box::MARGIN, Box::TOP);
 
@@ -540,7 +540,7 @@ void ElementDocument::ProcessDefaultAction(Event& event)
 		{
 			Element* focus_node = GetFocusLeafNode();
 
-			if (focus_node && focus_node->GetComputedValues().tab_index == Style::TabIndex::Auto)
+			if (focus_node && focus_node->GetComputedValues().tab_index() == Style::TabIndex::Auto)
 			{
 				focus_node->Click();
 				event.StopPropagation();
@@ -562,10 +562,10 @@ static CanFocus CanFocusElement(Element* element)
 
 	const ComputedValues& computed = element->GetComputedValues();
 
-	if (computed.focus == Style::Focus::None)
+	if (computed.focus() == Style::Focus::None)
 		return CanFocus::NoAndNoChildren;
 
-	if (computed.tab_index == Style::TabIndex::Auto)
+	if (computed.tab_index() == Style::TabIndex::Auto)
 		return CanFocus::Yes;
 
 	return CanFocus::No;

+ 6 - 5
Source/Core/ElementHandle.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "ElementHandle.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/ElementDocument.h"
 #include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../Include/RmlUi/Core/Property.h"
@@ -95,7 +96,7 @@ void ElementHandle::ProcessDefaultAction(Event& event)
 			}
 			if (size_target)
 				size_original_size = size_target->GetBox().GetSize(
-					(size_target->GetComputedValues().box_sizing == Style::BoxSizing::BorderBox)
+					(size_target->GetComputedValues().box_sizing() == Style::BoxSizing::BorderBox)
 					? Box::BORDER
 					: Box::CONTENT);
 		}
@@ -117,13 +118,13 @@ void ElementHandle::ProcessDefaultAction(Event& event)
 				const auto& computed = size_target->GetComputedValues();
 
 				// Check if we have auto-margins; if so, they have to be set to the current margins.
-				if (computed.margin_top.type == Margin::Auto)
+				if (computed.margin_top().type == Margin::Auto)
 					size_target->SetProperty(PropertyId::MarginTop, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::TOP)), Property::PX));
-				if (computed.margin_right.type == Margin::Auto)
+				if (computed.margin_right().type == Margin::Auto)
 					size_target->SetProperty(PropertyId::MarginRight, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::RIGHT)), Property::PX));
-				if (computed.margin_bottom.type == Margin::Auto)
+				if (computed.margin_bottom().type == Margin::Auto)
 					size_target->SetProperty(PropertyId::MarginBottom, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM)), Property::PX));
-				if (computed.margin_left.type == Margin::Auto)
+				if (computed.margin_left().type == Margin::Auto)
 					size_target->SetProperty(PropertyId::MarginLeft, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::LEFT)), Property::PX));
 
 				float new_x = Math::RoundFloat(size_original_size.x + delta.x);

+ 5 - 4
Source/Core/ElementScroll.cpp

@@ -27,13 +27,14 @@
  */
 
 #include "../../Include/RmlUi/Core/ElementScroll.h"
-#include "LayoutDetails.h"
-#include "WidgetScroll.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Context.h"
 #include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../Include/RmlUi/Core/Event.h"
 #include "../../Include/RmlUi/Core/Factory.h"
+#include "LayoutDetails.h"
+#include "WidgetScroll.h"
 
 namespace Rml {
 
@@ -77,7 +78,7 @@ void ElementScroll::EnableScrollbar(Orientation orientation, float element_width
 		if (box.GetSize().y < 0)
 			scrollbars[orientation].size = box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) +
 										   box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT) +
-										   ResolveValue(scrollbars[orientation].element->GetComputedValues().height, element_width);
+										   ResolveValue(scrollbars[orientation].element->GetComputedValues().height(), element_width);
 		else
 			scrollbars[orientation].size = box.GetSize(Box::MARGIN).y;
 	}
@@ -173,7 +174,7 @@ void ElementScroll::FormatScrollbars()
 		}
 
 		float slider_length = containing_block[1 - i];
-		float user_scrollbar_margin = scrollbars[i].element->GetComputedValues().scrollbar_margin;
+		float user_scrollbar_margin = scrollbars[i].element->GetComputedValues().scrollbar_margin();
 		float min_scrollbar_margin = GetScrollbarSize(i == VERTICAL ? HORIZONTAL : VERTICAL);
 		slider_length -= Math::Max(user_scrollbar_margin, min_scrollbar_margin);
 

+ 113 - 157
Source/Core/ElementStyle.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "ElementStyle.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Context.h"
 #include "../../Include/RmlUi/Core/Core.h"
 #include "../../Include/RmlUi/Core/ElementDocument.h"
@@ -370,14 +371,14 @@ const PropertyMap& ElementStyle::GetLocalStyleProperties() const
 
 static float ComputeLength(const Property* property, Element* element)
 {
-	const float font_size = element->GetComputedValues().font_size;
-	float doc_font_size = DefaultComputedValues.font_size;
+	const float font_size = element->GetComputedValues().font_size();
+	float doc_font_size = DefaultComputedValues.font_size();
 	float dp_ratio = 1.0f;
 	Vector2f vp_dimensions(1.0f);
 
 	if (ElementDocument* document = element->GetOwnerDocument())
 	{
-		doc_font_size = document->GetComputedValues().font_size;
+		doc_font_size = document->GetComputedValues().font_size();
 
 		if (Context* context = document->GetContext())
 		{
@@ -432,12 +433,12 @@ float ElementStyle::ResolveLength(const Property* property, RelativeTarget relat
 		base_value = element->GetContainingBlock().y;
 		break;
 	case RelativeTarget::FontSize:
-		base_value = element->GetComputedValues().font_size;
+		base_value = element->GetComputedValues().font_size();
 		break;
 	case RelativeTarget::ParentFontSize:
 	{
 		auto p = element->GetParentNode();
-		base_value = (p ? p->GetComputedValues().font_size : DefaultComputedValues.font_size);
+		base_value = (p ? p->GetComputedValues().font_size() : DefaultComputedValues.font_size());
 	}
 		break;
 	case RelativeTarget::LineHeight:
@@ -557,30 +558,35 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 	//   3. Assign any local properties (from inline style or stylesheet)
 	//   4. Dirty properties in children that are inherited
 
-	const float font_size_before = values.font_size;
-	const Style::LineHeight line_height_before = values.line_height;
+	const float font_size_before = values.font_size();
+	const Style::LineHeight line_height_before = values.line_height();
 
 	// The next flag is just a small optimization, if the element was just created we don't need to copy all the default values.
 	if (!values_are_default_initialized)
 	{
 		// This needs to be done in case some properties were removed and thus not in our local style anymore.
 		// If we skipped this, the old dirty value would be unmodified, instead, now it is set to its default value.
-		// Strictly speaking, we only really need to do this for the dirty values, and only non-inherited. However,
-		// it seems assigning the whole thing is faster in most cases.
-		values = DefaultComputedValues;
+		// Strictly speaking, we only really need to do this for the dirty, non-inherited values. However, in most
+		// cases it seems simply assigning all non-inherited values is faster than iterating the dirty properties.
+		values.CopyNonInherited(DefaultComputedValues);
 	}
 
+	if (parent_values)
+		values.CopyInherited(*parent_values);
+	else if (!values_are_default_initialized)
+		values.CopyInherited(DefaultComputedValues);
+
 	bool dirty_em_properties = false;
 
 	// Always do font-size first if dirty, because of em-relative values
 	if(dirty_properties.Contains(PropertyId::FontSize))
 	{
 		if (auto p = GetLocalProperty(PropertyId::FontSize))
-			values.font_size = ComputeFontsize(*p, values, parent_values, document_values, dp_ratio, vp_dimensions);
+			values.font_size(ComputeFontsize(*p, values, parent_values, document_values, dp_ratio, vp_dimensions));
 		else if (parent_values)
-			values.font_size = parent_values->font_size;
+			values.font_size(parent_values->font_size());
 		
-		if (font_size_before != values.font_size)
+		if (font_size_before != values.font_size())
 		{
 			dirty_em_properties = true;
 			dirty_properties.Insert(PropertyId::LineHeight);
@@ -588,65 +594,39 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 	}
 	else
 	{
-		values.font_size = font_size_before;
+		values.font_size(font_size_before);
 	}
 
-	const float font_size = values.font_size;
-	const float document_font_size = (document_values ? document_values->font_size : DefaultComputedValues.font_size);
-
+	const float font_size = values.font_size();
+	const float document_font_size = (document_values ? document_values->font_size() : DefaultComputedValues.font_size());
 
 	// Since vertical-align depends on line-height we compute this before iteration
 	if(dirty_properties.Contains(PropertyId::LineHeight))
 	{
 		if (auto p = GetLocalProperty(PropertyId::LineHeight))
 		{
-			values.line_height = ComputeLineHeight(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.line_height(ComputeLineHeight(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 		}
 		else if (parent_values)
 		{
 			// Line height has a special inheritance case for numbers/percent: they inherit them directly instead of computed length, but for lengths, they inherit the length.
 			// See CSS specs for details. Percent is already converted to number.
-			if (parent_values->line_height.inherit_type == Style::LineHeight::Number)
-				values.line_height = Style::LineHeight(font_size * parent_values->line_height.inherit_value, Style::LineHeight::Number, parent_values->line_height.inherit_value);
+			if (parent_values->line_height().inherit_type == Style::LineHeight::Number)
+				values.line_height() = Style::LineHeight(font_size * parent_values->line_height().inherit_value, Style::LineHeight::Number,
+					parent_values->line_height().inherit_value);
 			else
-				values.line_height = parent_values->line_height;
+				values.line_height(parent_values->line_height());
 		}
 
-		if(line_height_before.value != values.line_height.value || line_height_before.inherit_value != values.line_height.inherit_value)
+		if (line_height_before.value != values.line_height().value || line_height_before.inherit_value != values.line_height().inherit_value)
 			dirty_properties.Insert(PropertyId::VerticalAlign);
 	}
 	else
 	{
-		values.line_height = line_height_before;
-	}
-
-
-	if (parent_values)
-	{
-		// Inherited properties are copied here, but may be overwritten below by locally defined properties
-		// Line-height and font-size are computed above
-		values.color = parent_values->color;
-		values.opacity = parent_values->opacity;
-
-		values.font_family = parent_values->font_family;
-		values.font_style = parent_values->font_style;
-		values.font_weight = parent_values->font_weight;
-		values.font_face_handle = parent_values->font_face_handle;
-
-		values.text_align = parent_values->text_align;
-		values.text_decoration = parent_values->text_decoration;
-		values.text_transform = parent_values->text_transform;
-		values.white_space = parent_values->white_space;
-		values.word_break = parent_values->word_break;
-
-		values.cursor = parent_values->cursor;
-		values.focus = parent_values->focus;
-
-		values.pointer_events = parent_values->pointer_events;
-		
-		values.has_font_effect = parent_values->has_font_effect;
+		values.line_height(line_height_before);
 	}
 
+	bool dirty_font_face_handle = false;
 
 	for (auto it = Iterate(); !it.AtEnd(); ++it)
 	{
@@ -662,282 +642,257 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 		switch (id)
 		{
 		case PropertyId::MarginTop:
-			values.margin_top = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.margin_top(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::MarginRight:
-			values.margin_right = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.margin_right(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::MarginBottom:
-			values.margin_bottom = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.margin_bottom(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::MarginLeft:
-			values.margin_left = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.margin_left(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
 		case PropertyId::PaddingTop:
-			values.padding_top = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.padding_top(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::PaddingRight:
-			values.padding_right = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.padding_right(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::PaddingBottom:
-			values.padding_bottom = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.padding_bottom(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::PaddingLeft:
-			values.padding_left = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.padding_left(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
 		case PropertyId::BorderTopWidth:
-			values.border_top_width = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.border_top_width(ComputeBorderWidth(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions)));
 			break;
 		case PropertyId::BorderRightWidth:
-			values.border_right_width = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.border_right_width(ComputeBorderWidth(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions)));
 			break;
 		case PropertyId::BorderBottomWidth:
-			values.border_bottom_width = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.border_bottom_width(ComputeBorderWidth(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions)));
 			break;
 		case PropertyId::BorderLeftWidth:
-			values.border_left_width = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.border_left_width(ComputeBorderWidth(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions)));
 			break;
 
 		case PropertyId::BorderTopColor:
-			values.border_top_color = p->Get<Colourb>();
+			values.border_top_color(p->Get<Colourb>());
 			break;
 		case PropertyId::BorderRightColor:
-			values.border_right_color = p->Get<Colourb>();
+			values.border_right_color(p->Get<Colourb>());
 			break;
 		case PropertyId::BorderBottomColor:
-			values.border_bottom_color = p->Get<Colourb>();
+			values.border_bottom_color(p->Get<Colourb>());
 			break;
 		case PropertyId::BorderLeftColor:
-			values.border_left_color = p->Get<Colourb>();
+			values.border_left_color(p->Get<Colourb>());
 			break;
 
 		case PropertyId::BorderTopLeftRadius:
-			values.border_top_left_radius = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.border_top_left_radius(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::BorderTopRightRadius:
-			values.border_top_right_radius = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.border_top_right_radius(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::BorderBottomRightRadius:
-			values.border_bottom_right_radius = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.border_bottom_right_radius(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::BorderBottomLeftRadius:
-			values.border_bottom_left_radius = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.border_bottom_left_radius(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
 		case PropertyId::Display:
-			values.display = (Display)p->Get<int>();
+			values.display((Display)p->Get<int>());
 			break;
 		case PropertyId::Position:
-			values.position = (Position)p->Get<int>();
+			values.position((Position)p->Get<int>());
 			break;
 
 		case PropertyId::Top:
-			values.top = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.top(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::Right:
-			values.right = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.right(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::Bottom:
-			values.bottom = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.bottom(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::Left:
-			values.left = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.left(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
 		case PropertyId::Float:
-			values.float_ = (Float)p->Get<int>();
+			values.float_((Float)p->Get<int>());
 			break;
 		case PropertyId::Clear:
-			values.clear = (Clear)p->Get<int>();
+			values.clear((Clear)p->Get<int>());
 			break;
 		case PropertyId::BoxSizing:
-			values.box_sizing = (BoxSizing)p->Get<int>();
+			values.box_sizing((BoxSizing)p->Get<int>());
 			break;
 
 		case PropertyId::ZIndex:
-			values.z_index = (p->unit == Property::KEYWORD ? ZIndex(ZIndex::Auto) : ZIndex(ZIndex::Number, p->Get<float>()));
+			values.z_index((p->unit == Property::KEYWORD ? ZIndex(ZIndex::Auto) : ZIndex(ZIndex::Number, p->Get<float>())));
 			break;
 
 		case PropertyId::Width:
-			values.width = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.width(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::MinWidth:
-			values.min_width = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.min_width(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::MaxWidth:
-			values.max_width = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.max_width(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
 		case PropertyId::Height:
-			values.height = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.height(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::MinHeight:
-			values.min_height = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.min_height(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::MaxHeight:
-			values.max_height = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.max_height(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
 		case PropertyId::LineHeight:
 			// (Line-height computed above)
 			break;
 		case PropertyId::VerticalAlign:
-			values.vertical_align = ComputeVerticalAlign(p, values.line_height.value, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.vertical_align(ComputeVerticalAlign(p, values.line_height().value, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
 		case PropertyId::OverflowX:
-			values.overflow_x = (Overflow)p->Get< int >();
+			values.overflow_x((Overflow)p->Get< int >());
 			break;
 		case PropertyId::OverflowY:
-			values.overflow_y = (Overflow)p->Get< int >();
+			values.overflow_y((Overflow)p->Get< int >());
 			break;
 		case PropertyId::Clip:
-			values.clip = ComputeClip(p);
+			values.clip(ComputeClip(p));
 			break;
 		case PropertyId::Visibility:
-			values.visibility = (Visibility)p->Get< int >();
+			values.visibility((Visibility)p->Get< int >());
 			break;
 
 		case PropertyId::BackgroundColor:
-			values.background_color = p->Get<Colourb>();
+			values.background_color(p->Get<Colourb>());
 			break;
 		case PropertyId::Color:
-			values.color = p->Get<Colourb>();
+			values.color(p->Get<Colourb>());
 			break;
 		case PropertyId::ImageColor:
-			values.image_color = p->Get<Colourb>();
+			values.image_color(p->Get<Colourb>());
 			break;
 		case PropertyId::Opacity:
-			values.opacity = p->Get<float>();
+			values.opacity(p->Get<float>());
 			break;
 
 		case PropertyId::FontFamily:
-			values.font_family = ComputeFontFamily(p->Get<String>());
-			values.font_face_handle = 0;
+			// Fetched from element's properties.
+			dirty_font_face_handle = true;
 			break;
 		case PropertyId::FontStyle:
-			values.font_style = (FontStyle)p->Get< int >();
-			values.font_face_handle = 0;
+			values.font_style((FontStyle)p->Get< int >());
+			dirty_font_face_handle = true;
 			break;
 		case PropertyId::FontWeight:
-			values.font_weight = (FontWeight)p->Get< int >();
-			values.font_face_handle = 0;
+			values.font_weight((FontWeight)p->Get< int >());
+			dirty_font_face_handle = true;
 			break;
 		case PropertyId::FontSize:
 			// (font-size computed above)
-			values.font_face_handle = 0;
+			dirty_font_face_handle = true;
 			break;
 
 		case PropertyId::TextAlign:
-			values.text_align = (TextAlign)p->Get< int >();
+			values.text_align((TextAlign)p->Get<int>());
 			break;
 		case PropertyId::TextDecoration:
-			values.text_decoration = (TextDecoration)p->Get< int >();
+			values.text_decoration((TextDecoration)p->Get<int>());
 			break;
 		case PropertyId::TextTransform:
-			values.text_transform = (TextTransform)p->Get< int >();
+			values.text_transform((TextTransform)p->Get<int>());
 			break;
 		case PropertyId::WhiteSpace:
-			values.white_space = (WhiteSpace)p->Get< int >();
+			values.white_space((WhiteSpace)p->Get<int>());
 			break;
 		case PropertyId::WordBreak:
-			values.word_break = (WordBreak)p->Get< int >();
+			values.word_break((WordBreak)p->Get<int>());
 			break;
 
 		case PropertyId::RowGap:
-			values.row_gap = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.row_gap(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::ColumnGap:
-			values.column_gap = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions);
-			break;
-
-		case PropertyId::Cursor:
-			values.cursor = p->Get< String >();
+			values.column_gap(ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
 		case PropertyId::Drag:
-			values.drag = (Drag)p->Get< int >();
+			values.drag((Drag)p->Get< int >());
 			break;
 		case PropertyId::TabIndex:
-			values.tab_index = (TabIndex)p->Get< int >();
+			values.tab_index((TabIndex)p->Get< int >());
 			break;
 		case PropertyId::Focus:
-			values.focus = (Focus)p->Get<int>();
+			values.focus((Focus)p->Get<int>());
 			break;
 		case PropertyId::ScrollbarMargin:
-			values.scrollbar_margin = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.scrollbar_margin(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::PointerEvents:
-			values.pointer_events = (PointerEvents)p->Get<int>();
+			values.pointer_events((PointerEvents)p->Get<int>());
 			break;
 
 		case PropertyId::Perspective:
-			values.perspective = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.perspective(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::PerspectiveOriginX:
-			values.perspective_origin_x = ComputeOrigin(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.perspective_origin_x(ComputeOrigin(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::PerspectiveOriginY:
-			values.perspective_origin_y = ComputeOrigin(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.perspective_origin_y(ComputeOrigin(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
-		case PropertyId::Transform:
-			values.transform = p->Get<TransformPtr>();
-			break;
 		case PropertyId::TransformOriginX:
-			values.transform_origin_x = ComputeOrigin(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.transform_origin_x(ComputeOrigin(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::TransformOriginY:
-			values.transform_origin_y = ComputeOrigin(p, font_size, document_font_size, dp_ratio, vp_dimensions);
+			values.transform_origin_y(ComputeOrigin(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 		case PropertyId::TransformOriginZ:
-			values.transform_origin_z = ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions);
-			break;
-
-		case PropertyId::Transition:
-			values.transition = p->Get<TransitionList>();
-			break;
-		case PropertyId::Animation:
-			values.animation = p->Get<AnimationList>();
+			values.transform_origin_z(ComputeLength(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
 		case PropertyId::Decorator:
-			values.has_decorator = (p->unit == Property::DECORATOR);
+			values.has_decorator(p->unit == Property::DECORATOR);
 			break;
 		case PropertyId::FontEffect:
-			values.has_font_effect = (p->unit == Property::FONTEFFECT);
+			values.has_font_effect((p->unit == Property::FONTEFFECT));
+			break;
+		case PropertyId::FlexBasis:
+			values.flex_basis(ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions));
 			break;
 
+		// Fetched from element's properties.
+		case PropertyId::Cursor:
+		case PropertyId::Transform:
+		case PropertyId::Transition:
+		case PropertyId::Animation:
 		case PropertyId::AlignContent:
-			values.align_content = (AlignContent)p->Get<int>();
-			break;
 		case PropertyId::AlignItems:
-			values.align_items = (AlignItems)p->Get<int>();
-			break;
 		case PropertyId::AlignSelf:
-			values.align_self = (AlignSelf)p->Get<int>();
-			break;
-		case PropertyId::FlexBasis:
-			values.flex_basis = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, vp_dimensions);
-			break;
 		case PropertyId::FlexDirection:
-			values.flex_direction = (FlexDirection)p->Get<int>();
-			break;
 		case PropertyId::FlexGrow:
-			values.flex_grow = p->Get<float>();
-			break;
 		case PropertyId::FlexShrink:
-			values.flex_shrink = p->Get<float>();
-			break;
 		case PropertyId::FlexWrap:
-			values.flex_wrap = (FlexWrap)p->Get<int>();
-			break;
 		case PropertyId::JustifyContent:
-			values.justify_content = (JustifyContent)p->Get<int>();
 			break;
-
 		// Unhandled properties. Must be manually retrieved with 'GetProperty()'.
 		case PropertyId::FillImage:
 		case PropertyId::CaretColor:
@@ -951,10 +906,11 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 	}
 
 	// The font-face handle is nulled when local font properties are set. In that case we need to retrieve a new handle.
-	if (!values.font_face_handle)
+	if (dirty_font_face_handle)
 	{
 		RMLUI_ZoneScopedN("FontFaceHandle");
-		values.font_face_handle = GetFontEngineInterface()->GetFontFaceHandle(values.font_family, values.font_style, values.font_weight, (int)values.font_size);
+		values.font_face_handle(
+			GetFontEngineInterface()->GetFontFaceHandle(values.font_family(), values.font_style(), values.font_weight(), (int)values.font_size()));
 	}
 
 	// Next, pass inheritable dirty properties onto our children

+ 9 - 9
Source/Core/ElementText.cpp

@@ -171,7 +171,7 @@ bool ElementText::GenerateToken(float& token_width, int line_begin)
 	// Determine how we are processing white-space while formatting the text.
 	using namespace Style;
 	auto& computed = GetComputedValues();
-	WhiteSpace white_space_property = computed.white_space;
+	WhiteSpace white_space_property = computed.white_space();
 	bool collapse_white_space = white_space_property == WhiteSpace::Normal ||
 								white_space_property == WhiteSpace::Nowrap ||
 								white_space_property == WhiteSpace::Preline;
@@ -182,7 +182,7 @@ bool ElementText::GenerateToken(float& token_width, int line_begin)
 	const char* token_begin = text.c_str() + line_begin;
 	String token;
 
-	BuildToken(token, token_begin, text.c_str() + text.size(), true, collapse_white_space, break_at_endline, computed.text_transform, true);
+	BuildToken(token, token_begin, text.c_str() + text.size(), true, collapse_white_space, break_at_endline, computed.text_transform(), true);
 	token_width = (float) GetFontEngineInterface()->GetStringWidth(font_face_handle, token);
 
 	return LastToken(token_begin, text.c_str() + text.size(), collapse_white_space, break_at_endline);
@@ -207,7 +207,7 @@ bool ElementText::GenerateLine(String& line, int& line_length, float& line_width
 	// Determine how we are processing white-space while formatting the text.
 	using namespace Style;
 	auto& computed = GetComputedValues();
-	WhiteSpace white_space_property = computed.white_space;
+	WhiteSpace white_space_property = computed.white_space();
 	bool collapse_white_space = white_space_property == WhiteSpace::Normal ||
 								white_space_property == WhiteSpace::Nowrap ||
 								white_space_property == WhiteSpace::Preline;
@@ -219,8 +219,8 @@ bool ElementText::GenerateLine(String& line, int& line_length, float& line_width
 							white_space_property == WhiteSpace::Prewrap ||
 							white_space_property == WhiteSpace::Preline;
 
-	TextTransform text_transform_property = computed.text_transform;
-	WordBreak word_break = computed.word_break;
+	TextTransform text_transform_property = computed.text_transform();
+	WordBreak word_break = computed.word_break();
 
 	FontEngineInterface* font_engine_interface = GetFontEngineInterface();
 
@@ -355,10 +355,10 @@ void ElementText::OnPropertyChange(const PropertyIdSet& changed_properties)
 	if (changed_properties.Contains(PropertyId::Color) ||
 		changed_properties.Contains(PropertyId::Opacity))
 	{
-		const float new_opacity = computed.opacity;
+		const float new_opacity = computed.opacity();
 		const bool opacity_changed = opacity != new_opacity;
 
-		Colourb new_colour = computed.color;
+		Colourb new_colour = computed.color();
 		new_colour.alpha = byte(new_opacity * float(new_colour.alpha));
 		colour_changed = colour != new_colour;
 
@@ -392,7 +392,7 @@ void ElementText::OnPropertyChange(const PropertyIdSet& changed_properties)
 
 	if (changed_properties.Contains(PropertyId::TextDecoration))
 	{
-		decoration_property = computed.text_decoration;
+		decoration_property = computed.text_decoration();
 	}
 
 	if (font_face_changed)
@@ -435,7 +435,7 @@ bool ElementText::UpdateFontEffects()
 
 	// Fetch the font-effect for this text element
 	const FontEffectList* font_effects = &empty_font_effects;
-	if (GetComputedValues().has_font_effect)
+	if (GetComputedValues().has_font_effect())
 	{
 		if (const Property* p = GetProperty(PropertyId::FontEffect))
 			if (FontEffectsPtr effects = p->Get<FontEffectsPtr>())

+ 6 - 6
Source/Core/ElementUtilities.cpp

@@ -58,7 +58,7 @@ static void SetBox(Element* element)
 	Box box;
 	LayoutDetails::BuildBox(box, containing_block, element);
 
-	if (element->GetComputedValues().height.type != Style::Height::Auto)
+	if (element->GetComputedValues().height().type != Style::Height::Auto)
 		box.SetContent(Vector2f(box.GetSize().x, containing_block.y));
 
 	element->SetBox(box);
@@ -170,7 +170,7 @@ bool ElementUtilities::GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_d
 	clip_origin = Vector2i(-1, -1);
 	clip_dimensions = Vector2i(-1, -1);
 
-	Clip target_element_clip = element->GetComputedValues().clip;
+	Clip target_element_clip = element->GetComputedValues().clip();
 	if (target_element_clip == Clip::Type::None)
 		return false;
 
@@ -184,10 +184,10 @@ bool ElementUtilities::GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_d
 	while (clipping_element != nullptr)
 	{
 		const ComputedValues& clip_computed = clipping_element->GetComputedValues();
-		const bool clip_enabled = (clip_computed.overflow_x != Style::Overflow::Visible || clip_computed.overflow_y != Style::Overflow::Visible);
-		const bool clip_always = (clip_computed.clip == Clip::Type::Always);
-		const bool clip_none = (clip_computed.clip == Clip::Type::None);
-		const int clip_number = clip_computed.clip.GetNumber();
+		const bool clip_enabled = (clip_computed.overflow_x() != Style::Overflow::Visible || clip_computed.overflow_y() != Style::Overflow::Visible);
+		const bool clip_always = (clip_computed.clip() == Clip::Type::Always);
+		const bool clip_none = (clip_computed.clip() == Clip::Type::None);
+		const int clip_number = clip_computed.clip().GetNumber();
 
 		// Merge the existing clip region with the current clip region if we aren't ignoring clip regions.
 		if ((clip_always || clip_enabled) && num_ignored_clips == 0)

+ 7 - 6
Source/Core/Elements/ElementImage.cpp

@@ -27,13 +27,14 @@
  */
 
 #include "ElementImage.h"
-#include "../TextureDatabase.h"
-#include "../../../Include/RmlUi/Core/URL.h"
-#include "../../../Include/RmlUi/Core/PropertyIdSet.h"
-#include "../../../Include/RmlUi/Core/GeometryUtilities.h"
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../../Include/RmlUi/Core/ElementDocument.h"
 #include "../../../Include/RmlUi/Core/ElementUtilities.h"
+#include "../../../Include/RmlUi/Core/GeometryUtilities.h"
+#include "../../../Include/RmlUi/Core/PropertyIdSet.h"
 #include "../../../Include/RmlUi/Core/StyleSheet.h"
+#include "../../../Include/RmlUi/Core/URL.h"
+#include "../TextureDatabase.h"
 
 namespace Rml {
 
@@ -207,8 +208,8 @@ void ElementImage::GenerateGeometry()
 
 	const ComputedValues& computed = GetComputedValues();
 
-	float opacity = computed.opacity;
-	Colourb quad_colour = computed.image_color;
+	float opacity = computed.opacity();
+	Colourb quad_colour = computed.image_color();
     quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha);
 	
 	Vector2f quad_size = GetBox().GetSize(Box::CONTENT).Round();

+ 7 - 6
Source/Core/Elements/ElementProgress.cpp

@@ -27,13 +27,14 @@
  */
 
 #include "../../../Include/RmlUi/Core/Elements/ElementProgress.h"
-#include "../../../Include/RmlUi/Core/Math.h"
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../../Include/RmlUi/Core/ElementDocument.h"
+#include "../../../Include/RmlUi/Core/ElementUtilities.h"
+#include "../../../Include/RmlUi/Core/Factory.h"
 #include "../../../Include/RmlUi/Core/GeometryUtilities.h"
+#include "../../../Include/RmlUi/Core/Math.h"
 #include "../../../Include/RmlUi/Core/PropertyIdSet.h"
-#include "../../../Include/RmlUi/Core/Factory.h"
-#include "../../../Include/RmlUi/Core/ElementDocument.h"
 #include "../../../Include/RmlUi/Core/StyleSheet.h"
-#include "../../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../../Include/RmlUi/Core/URL.h"
 #include <algorithm>
 
@@ -259,8 +260,8 @@ void ElementProgress::GenerateGeometry()
 	Colourb quad_colour;
 	{
 		const ComputedValues& computed = GetComputedValues();
-		const float opacity = computed.opacity;
-		quad_colour = computed.image_color;
+		const float opacity = computed.opacity();
+		quad_colour = computed.image_color();
 		quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha);
 	}
 

+ 2 - 1
Source/Core/Elements/WidgetDropDown.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "WidgetDropDown.h"
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../../Include/RmlUi/Core/Context.h"
 #include "../../../Include/RmlUi/Core/ElementDocument.h"
 #include "../../../Include/RmlUi/Core/Math.h"
@@ -520,7 +521,7 @@ void WidgetDropDown::ProcessEvent(Event& event)
 				element = element->GetParentNode();
 			}
 
-			if (selection_element->GetComputedValues().visibility == Style::Visibility::Hidden)
+			if (selection_element->GetComputedValues().visibility() == Style::Visibility::Hidden)
 				ShowSelectBox(true);
 			else
 				ShowSelectBox(false);

+ 2 - 1
Source/Core/Elements/WidgetSlider.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "WidgetSlider.h"
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../../Include/RmlUi/Core/Elements/ElementFormControl.h"
 #include "../../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../../Include/RmlUi/Core/Factory.h"
@@ -342,7 +343,7 @@ void WidgetSlider::FormatBar()
 	Vector2f bar_box_content = bar_box.GetSize();
 	if (orientation == HORIZONTAL)
 	{
-		if (computed.height.type == Style::Height::Auto)
+		if (computed.height().type == Style::Height::Auto)
 			bar_box_content.y = parent->GetBox().GetSize().y;
 	}
 

+ 9 - 8
Source/Core/Elements/WidgetTextInput.cpp

@@ -27,19 +27,20 @@
  */
 
 #include "WidgetTextInput.h"
-#include "ElementTextSelection.h"
-#include "../../../Include/RmlUi/Core/Elements/ElementFormControl.h"
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../../Include/RmlUi/Core/Core.h"
 #include "../../../Include/RmlUi/Core/ElementScroll.h"
 #include "../../../Include/RmlUi/Core/ElementText.h"
 #include "../../../Include/RmlUi/Core/ElementUtilities.h"
+#include "../../../Include/RmlUi/Core/Elements/ElementFormControl.h"
+#include "../../../Include/RmlUi/Core/Factory.h"
 #include "../../../Include/RmlUi/Core/GeometryUtilities.h"
 #include "../../../Include/RmlUi/Core/Input.h"
-#include "../../../Include/RmlUi/Core/Factory.h"
 #include "../../../Include/RmlUi/Core/Math.h"
-#include "../../../Include/RmlUi/Core/SystemInterface.h"
 #include "../../../Include/RmlUi/Core/StringUtilities.h"
+#include "../../../Include/RmlUi/Core/SystemInterface.h"
 #include "../Clock.h"
+#include "ElementTextSelection.h"
 #include <algorithm>
 #include <limits.h>
 
@@ -193,7 +194,7 @@ void WidgetTextInput::UpdateSelectionColours()
 		colour = colour_property->Get< Colourb >();
 	else
 	{
-		colour = parent->GetComputedValues().color;
+		colour = parent->GetComputedValues().color();
 		colour.red = 255 - colour.red;
 		colour.green = 255 - colour.green;
 		colour.blue = 255 - colour.blue;
@@ -928,8 +929,8 @@ void WidgetTextInput::FormatElement()
 	ElementScroll* scroll = parent->GetElementScroll();
 	float width = parent->GetBox().GetSize(Box::PADDING).x;
 
-	Overflow x_overflow_property = parent->GetComputedValues().overflow_x;
-	Overflow y_overflow_property = parent->GetComputedValues().overflow_y;
+	Overflow x_overflow_property = parent->GetComputedValues().overflow_x();
+	Overflow y_overflow_property = parent->GetComputedValues().overflow_y();
 
 	if (x_overflow_property == Overflow::Scroll)
 		scroll->EnableScrollbar(ElementScroll::HORIZONTAL, width);
@@ -1144,7 +1145,7 @@ void WidgetTextInput::GenerateCursor()
 	cursor_size.x = Math::RoundFloat( ElementUtilities::GetDensityIndependentPixelRatio(text_element) );
 	cursor_size.y = text_element->GetLineHeight() + 2.0f;
 
-	Colourb color = parent->GetComputedValues().color;
+	Colourb color = parent->GetComputedValues().color();
 
 	if (const Property* property = parent->GetProperty(PropertyId::CaretColor))
 	{

+ 1 - 1
Source/Core/FontEngineDefault/FontFace.h

@@ -29,7 +29,7 @@
 #ifndef RMLUI_CORE_FONTENGINEDEFAULT_FONTFACE_H
 #define RMLUI_CORE_FONTENGINEDEFAULT_FONTFACE_H
 
-#include "../../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../../Include/RmlUi/Core/StyleTypes.h"
 #include "FontTypes.h"
 
 namespace Rml {

+ 1 - 0
Source/Core/FontEngineDefault/FontFamily.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "FontFamily.h"
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
 #include "FontFace.h"
 
 namespace Rml {

+ 1 - 1
Source/Core/FontEngineDefault/FontProvider.h

@@ -30,7 +30,7 @@
 #define RMLUI_CORE_FONTENGINEDEFAULT_FONTPROVIDER_H
 
 #include "../../../Include/RmlUi/Core/Types.h"
-#include "../../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../../Include/RmlUi/Core/StyleTypes.h"
 #include "FontTypes.h"
 
 namespace Rml {

+ 2 - 2
Source/Core/FontEngineDefault/FontTypes.h

@@ -29,9 +29,9 @@
 #ifndef RMLUI_CORE_FONTENGINEDEFAULT_FONTTYPES_H
 #define RMLUI_CORE_FONTENGINEDEFAULT_FONTTYPES_H
 
-#include "../../../Include/RmlUi/Core/Types.h"
-#include "../../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../../Include/RmlUi/Core/FontGlyph.h"
+#include "../../../Include/RmlUi/Core/StyleTypes.h"
+#include "../../../Include/RmlUi/Core/Types.h"
 
 namespace Rml {
 

+ 1 - 0
Source/Core/FontEngineDefault/FreeTypeInterface.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "FreeTypeInterface.h"
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../../Include/RmlUi/Core/Log.h"
 
 #include <string.h>

+ 13 - 12
Source/Core/LayoutBlockBox.cpp

@@ -27,14 +27,15 @@
  */
 
 #include "LayoutBlockBox.h"
-#include "LayoutBlockBoxSpace.h"
-#include "LayoutEngine.h"
-#include "LayoutDetails.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
-#include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../Include/RmlUi/Core/ElementScroll.h"
-#include "../../Include/RmlUi/Core/Property.h"
+#include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../Include/RmlUi/Core/Profiling.h"
+#include "../../Include/RmlUi/Core/Property.h"
+#include "LayoutBlockBoxSpace.h"
+#include "LayoutDetails.h"
+#include "LayoutEngine.h"
 #include <float.h>
 
 namespace Rml {
@@ -89,7 +90,7 @@ LayoutBlockBox::LayoutBlockBox(LayoutBlockBox* _parent, Element* _element, const
 			if (self_offset_parent != this)
 			{
 				// Get the next position within our offset parent's containing block.
-				parent->PositionBlockBox(position, box, element ? element->GetComputedValues().clear : Style::Clear::None);
+				parent->PositionBlockBox(position, box, element ? element->GetComputedValues().clear() : Style::Clear::None);
 				element->SetOffset(position - (self_offset_parent->GetPosition() - offset_root->GetPosition()), self_offset_parent->GetElement());
 			}
 			else
@@ -100,11 +101,11 @@ LayoutBlockBox::LayoutBlockBox(LayoutBlockBox* _parent, Element* _element, const
 	if (element)
 	{
 		const auto& computed = element->GetComputedValues();
-		wrap_content = computed.white_space != Style::WhiteSpace::Nowrap;
+		wrap_content = computed.white_space() != Style::WhiteSpace::Nowrap;
 
 		// Determine if this element should have scrollbars or not, and create them if so.
-		overflow_x_property = computed.overflow_x;
-		overflow_y_property = computed.overflow_y;
+		overflow_x_property = computed.overflow_x();
+		overflow_y_property = computed.overflow_y();
 
 		if (overflow_x_property == Style::Overflow::Scroll)
 			element->GetElementScroll()->EnableScrollbar(ElementScroll::HORIZONTAL, box.GetSize(Box::PADDING).x);
@@ -118,7 +119,7 @@ LayoutBlockBox::LayoutBlockBox(LayoutBlockBox* _parent, Element* _element, const
 
 		// Store relatively positioned elements with their containing block so that their offset can be updated after their containing block has been
 		// sized.
-		if (self_offset_parent != this && computed.position == Style::Position::Relative)
+		if (self_offset_parent != this && computed.position() == Style::Position::Relative)
 			self_offset_parent->relative_elements.push_back(element);
 	}
 	else
@@ -631,13 +632,13 @@ float LayoutBlockBox::GetShrinkToFitWidth() const
 			auto& computed = element->GetComputedValues();
 			const float block_width = box.GetSize(Box::CONTENT).x;
 
-			if(computed.width.type == Style::Width::Auto)
+			if (computed.width().type == Style::Width::Auto)
 			{
 				get_content_width_from_children();
 			}
 			else
 			{
-				float width_value = ResolveValue(computed.width, block_width);
+				float width_value = ResolveValue(computed.width(), block_width);
 				content_width = Math::Max(content_width, width_value);
 			}
 

+ 5 - 4
Source/Core/LayoutBlockBoxSpace.cpp

@@ -27,10 +27,11 @@
  */
 
 #include "LayoutBlockBoxSpace.h"
-#include "LayoutBlockBox.h"
-#include "LayoutEngine.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/ElementScroll.h"
+#include "LayoutBlockBox.h"
+#include "LayoutEngine.h"
 #include <float.h>
 
 namespace Rml {
@@ -65,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);
-	Style::Float float_property = element->GetComputedValues().float_;
+	Style::Float float_property = element->GetComputedValues().float_();
 
 	// 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)
@@ -75,7 +76,7 @@ float LayoutBlockBoxSpace::PositionBox(float cursor, Element* element)
 	}
 
 	// Shift the cursor down past to clear boxes, if necessary.
-	cursor = ClearBoxes(cursor, element->GetComputedValues().clear);
+	cursor = ClearBoxes(cursor, element->GetComputedValues().clear());
 
 	// Find a place to put this box.
 	Vector2f element_offset;

+ 1 - 1
Source/Core/LayoutBlockBoxSpace.h

@@ -29,7 +29,7 @@
 #ifndef RMLUI_CORE_LAYOUTBLOCKBOXSPACE_H
 #define RMLUI_CORE_LAYOUTBLOCKBOXSPACE_H
 
-#include "../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../Include/RmlUi/Core/StyleTypes.h"
 #include "../../Include/RmlUi/Core/Types.h"
 
 namespace Rml {

+ 48 - 49
Source/Core/LayoutDetails.cpp

@@ -27,11 +27,12 @@
  */
 
 #include "LayoutDetails.h"
-#include "LayoutEngine.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/ElementScroll.h"
 #include "../../Include/RmlUi/Core/Math.h"
 #include "../../Include/RmlUi/Core/Profiling.h"
+#include "LayoutEngine.h"
 #include <float.h>
 
 namespace Rml {
@@ -57,16 +58,16 @@ void LayoutDetails::BuildBox(Box& box, Vector2f containing_block, Element* eleme
 	const ComputedValues& computed = element->GetComputedValues();
 
 	// Calculate the padding area.
-	box.SetEdge(Box::PADDING, Box::TOP, Math::Max(0.0f, ResolveValue(computed.padding_top, containing_block.x)));
-	box.SetEdge(Box::PADDING, Box::RIGHT, Math::Max(0.0f, ResolveValue(computed.padding_right, containing_block.x)));
-	box.SetEdge(Box::PADDING, Box::BOTTOM, Math::Max(0.0f, ResolveValue(computed.padding_bottom, containing_block.x)));
-	box.SetEdge(Box::PADDING, Box::LEFT, Math::Max(0.0f, ResolveValue(computed.padding_left, containing_block.x)));
+	box.SetEdge(Box::PADDING, Box::TOP, Math::Max(0.0f, ResolveValue(computed.padding_top(), containing_block.x)));
+	box.SetEdge(Box::PADDING, Box::RIGHT, Math::Max(0.0f, ResolveValue(computed.padding_right(), containing_block.x)));
+	box.SetEdge(Box::PADDING, Box::BOTTOM, Math::Max(0.0f, ResolveValue(computed.padding_bottom(), containing_block.x)));
+	box.SetEdge(Box::PADDING, Box::LEFT, Math::Max(0.0f, ResolveValue(computed.padding_left(), containing_block.x)));
 
 	// Calculate the border area.
-	box.SetEdge(Box::BORDER, Box::TOP, Math::Max(0.0f, computed.border_top_width));
-	box.SetEdge(Box::BORDER, Box::RIGHT, Math::Max(0.0f, computed.border_right_width));
-	box.SetEdge(Box::BORDER, Box::BOTTOM, Math::Max(0.0f, computed.border_bottom_width));
-	box.SetEdge(Box::BORDER, Box::LEFT, Math::Max(0.0f, computed.border_left_width));
+	box.SetEdge(Box::BORDER, Box::TOP, Math::Max(0.0f, computed.border_top_width()));
+	box.SetEdge(Box::BORDER, Box::RIGHT, Math::Max(0.0f, computed.border_right_width()));
+	box.SetEdge(Box::BORDER, Box::BOTTOM, Math::Max(0.0f, computed.border_bottom_width()));
+	box.SetEdge(Box::BORDER, Box::LEFT, Math::Max(0.0f, computed.border_left_width()));
 
 	// Prepare sizing of the content area.
 	Vector2f content_area(-1, -1);
@@ -83,23 +84,23 @@ void LayoutDetails::BuildBox(Box& box, Vector2f containing_block, Element* eleme
 	// For inline non-replaced elements, width and height are ignored, so we can skip the calculations.
 	if (box_context == BoxContext::Block || box_context == BoxContext::FlexOrTable || replaced_element)
 	{
-		if (content_area.x < 0 && computed.width.type != Style::Width::Auto)
-			content_area.x = ResolveValue(computed.width, containing_block.x);
+		if (content_area.x < 0 && computed.width().type != Style::Width::Auto)
+			content_area.x = ResolveValue(computed.width(), containing_block.x);
 
-		if (content_area.y < 0 && computed.height.type != Style::Width::Auto)
-			content_area.y = ResolveValue(computed.height, containing_block.y);
+		if (content_area.y < 0 && computed.height().type != Style::Width::Auto)
+			content_area.y = ResolveValue(computed.height(), containing_block.y);
 
 		min_size = Vector2f(
-			ResolveValue(computed.min_width, containing_block.x),
-			ResolveValue(computed.min_height, containing_block.y)
+			ResolveValue(computed.min_width(), containing_block.x),
+			ResolveValue(computed.min_height(), containing_block.y)
 		);
 		max_size = Vector2f(
-			(computed.max_width.value < 0.f ? FLT_MAX : ResolveValue(computed.max_width, containing_block.x)),
-			(computed.max_height.value < 0.f ? FLT_MAX : ResolveValue(computed.max_height, containing_block.y))
+			(computed.max_width().value < 0.f ? FLT_MAX : ResolveValue(computed.max_width(), containing_block.x)),
+			(computed.max_height().value < 0.f ? FLT_MAX : ResolveValue(computed.max_height(), containing_block.y))
 		);
 
 		// Adjust sizes for the given box sizing model.
-		if (computed.box_sizing == Style::BoxSizing::BorderBox)
+		if (computed.box_sizing() == Style::BoxSizing::BorderBox)
 		{
 			const float border_padding_width = box.GetSizeAcross(Box::HORIZONTAL, Box::BORDER, Box::PADDING);
 			const float border_padding_height = box.GetSizeAcross(Box::VERTICAL, Box::BORDER, Box::PADDING);
@@ -144,10 +145,10 @@ void LayoutDetails::BuildBox(Box& box, float& min_height, float& max_height, Lay
 
 void LayoutDetails::GetMinMaxWidth(float& min_width, float& max_width, const ComputedValues& computed, const Box& box, float containing_block_width)
 {
-	min_width = ResolveValue(computed.min_width, containing_block_width);
-	max_width = (computed.max_width.value < 0.f ? FLT_MAX : ResolveValue(computed.max_width, containing_block_width));
+	min_width = ResolveValue(computed.min_width(), containing_block_width);
+	max_width = (computed.max_width().value < 0.f ? FLT_MAX : ResolveValue(computed.max_width(), containing_block_width));
 
-	if (computed.box_sizing == Style::BoxSizing::BorderBox)
+	if (computed.box_sizing() == Style::BoxSizing::BorderBox)
 	{
 		const float border_padding_width = box.GetSizeAcross(Box::HORIZONTAL, Box::BORDER, Box::PADDING);
 		min_width = BorderSizeToContentSize(min_width, border_padding_width);
@@ -158,10 +159,10 @@ void LayoutDetails::GetMinMaxWidth(float& min_width, float& max_width, const Com
 
 void LayoutDetails::GetMinMaxHeight(float& min_height, float& max_height, const ComputedValues& computed, const Box& box, float containing_block_height)
 {
-	min_height = ResolveValue(computed.min_height, containing_block_height);
-	max_height = (computed.max_height.value < 0.f ? FLT_MAX : ResolveValue(computed.max_height, containing_block_height));
+	min_height = ResolveValue(computed.min_height(), containing_block_height);
+	max_height = (computed.max_height().value < 0.f ? FLT_MAX : ResolveValue(computed.max_height(), containing_block_height));
 
-	if (computed.box_sizing == Style::BoxSizing::BorderBox)
+	if (computed.box_sizing() == Style::BoxSizing::BorderBox)
 	{
 		const float border_padding_height = box.GetSizeAcross(Box::VERTICAL, Box::BORDER, Box::PADDING);
 		min_height = BorderSizeToContentSize(min_height, border_padding_height);
@@ -223,10 +224,10 @@ void LayoutDetails::BuildBoxSizeAndMargins(Box& box, Vector2f min_size, Vector2f
 	{
 		// For inline elements, their calculations are straightforward. No worrying about auto margins and dimensions, etc.
 		// Evaluate the margins. Any declared as 'auto' will resolve to 0.
-		box.SetEdge(Box::MARGIN, Box::TOP, ResolveValue(computed.margin_top, containing_block.x));
-		box.SetEdge(Box::MARGIN, Box::RIGHT, ResolveValue(computed.margin_right, containing_block.x));
-		box.SetEdge(Box::MARGIN, Box::BOTTOM, ResolveValue(computed.margin_bottom, containing_block.x));
-		box.SetEdge(Box::MARGIN, Box::LEFT, ResolveValue(computed.margin_left, containing_block.x));
+		box.SetEdge(Box::MARGIN, Box::TOP, ResolveValue(computed.margin_top(), containing_block.x));
+		box.SetEdge(Box::MARGIN, Box::RIGHT, ResolveValue(computed.margin_right(), containing_block.x));
+		box.SetEdge(Box::MARGIN, Box::BOTTOM, ResolveValue(computed.margin_bottom(), containing_block.x));
+		box.SetEdge(Box::MARGIN, Box::LEFT, ResolveValue(computed.margin_left(), containing_block.x));
 	}
 	else
 	{
@@ -270,14 +271,14 @@ float LayoutDetails::GetShrinkToFitWidth(Element* element, Vector2f containing_b
 
 ComputedAxisSize LayoutDetails::BuildComputedHorizontalSize(const ComputedValues& computed)
 {
-	return ComputedAxisSize{computed.width, computed.min_width, computed.max_width, computed.padding_left, computed.padding_right,
-		computed.margin_left, computed.margin_right, computed.border_left_width, computed.border_right_width, computed.box_sizing};
+	return ComputedAxisSize{computed.width(), computed.min_width(), computed.max_width(), computed.padding_left(), computed.padding_right(),
+		computed.margin_left(), computed.margin_right(), computed.border_left_width(), computed.border_right_width(), computed.box_sizing()};
 }
 
 ComputedAxisSize LayoutDetails::BuildComputedVerticalSize(const ComputedValues& computed)
 {
-	return ComputedAxisSize{computed.height, computed.min_height, computed.max_height, computed.padding_top, computed.padding_bottom,
-		computed.margin_top, computed.margin_bottom, computed.border_top_width, computed.border_bottom_width, computed.box_sizing};
+	return ComputedAxisSize{computed.height(), computed.min_height(), computed.max_height(), computed.padding_top(), computed.padding_bottom(),
+		computed.margin_top(), computed.margin_bottom(), computed.border_top_width(), computed.border_bottom_width(), computed.box_sizing()};
 }
 
 void LayoutDetails::GetEdgeSizes(float& margin_a, float& margin_b, float& padding_border_a, float& padding_border_b,
@@ -390,7 +391,7 @@ void LayoutDetails::BuildBoxWidth(Box& box, const ComputedValues& computed, floa
 
 	for (int i = 0; i < 2; ++i)
 	{
-		const Style::Margin& margin_value = (i == 0 ? computed.margin_left : computed.margin_right);
+		const Style::Margin margin_value = (i == 0 ? computed.margin_left() : computed.margin_right());
 		if (margin_value.type == Style::Margin::Auto)
 		{
 			margins_auto[i] = true;
@@ -412,22 +413,20 @@ void LayoutDetails::BuildBoxWidth(Box& box, const ComputedValues& computed, floa
 		// Apply the shrink-to-fit algorithm here to find the width of the element.
 		// See CSS 2.1 section 10.3.7 for when this should be applied.
 		const bool shrink_to_fit = !replaced_element &&
-			(
-				(computed.float_ != Style::Float::None) ||
-				((computed.position == Style::Position::Absolute || computed.position == Style::Position::Fixed) && (computed.left.type == Style::Left::Auto || computed.right.type == Style::Right::Auto)) ||
-				(computed.display == Style::Display::InlineBlock)
-			);
+			((computed.float_() != Style::Float::None) ||
+				((computed.position() == Style::Position::Absolute || computed.position() == Style::Position::Fixed) &&
+					(computed.left().type == Style::Left::Auto || computed.right().type == Style::Right::Auto)) ||
+				(computed.display() == Style::Display::InlineBlock));
 
-		
 		float left = 0.0f, right = 0.0f;
 		// If we are dealing with an absolutely positioned element we need to
 		// consider if the left and right properties are set, since the width can be affected.
-		if (computed.position == Style::Position::Absolute || computed.position == Style::Position::Fixed)
+		if (computed.position() == Style::Position::Absolute || computed.position() == Style::Position::Fixed)
 		{
-			if (computed.left.type != Style::Left::Auto)
-				left = ResolveValue(computed.left, containing_block.x);
-			if (computed.right.type != Style::Right::Auto)
-				right = ResolveValue(computed.right, containing_block.x);
+			if (computed.left().type != Style::Left::Auto)
+				left = ResolveValue(computed.left(), containing_block.x);
+			if (computed.right().type != Style::Right::Auto)
+				right = ResolveValue(computed.right(), containing_block.x);
 		}
 
 		if (shrink_to_fit && override_shrink_to_fit_width < 0)
@@ -488,7 +487,7 @@ void LayoutDetails::BuildBoxHeight(Box& box, const ComputedValues& computed, flo
 
 	for (int i = 0; i < 2; ++i)
 	{
-		const Style::Margin& margin_value = (i == 0 ? computed.margin_top : computed.margin_bottom);
+		const Style::Margin margin_value = (i == 0 ? computed.margin_top() : computed.margin_bottom());
 		if (margin_value.type == Style::Margin::Auto)
 		{
 			margins_auto[i] = true;
@@ -512,14 +511,14 @@ void LayoutDetails::BuildBoxHeight(Box& box, const ComputedValues& computed, flo
 
 		// But if we are dealing with an absolutely positioned element we need to
 		// consider if the top and bottom properties are set, since the height can be affected.
-		if (computed.position == Style::Position::Absolute || computed.position == Style::Position::Fixed)
+		if (computed.position() == Style::Position::Absolute || computed.position() == Style::Position::Fixed)
 		{
 			float top = 0.0f, bottom = 0.0f;
 
-			if (computed.top.type != Style::Top::Auto && computed.bottom.type != Style::Bottom::Auto)
+			if (computed.top().type != Style::Top::Auto && computed.bottom().type != Style::Bottom::Auto)
 			{
-				top = ResolveValue(computed.top, containing_block_height );
-				bottom = ResolveValue(computed.bottom, containing_block_height );
+				top = ResolveValue(computed.top(), containing_block_height);
+				bottom = ResolveValue(computed.bottom(), containing_block_height);
 
 				// The height gets resolved to whatever is left of the containing block
 				content_area.y = containing_block_height - (top +

+ 1 - 1
Source/Core/LayoutDetails.h

@@ -29,7 +29,7 @@
 #ifndef RMLUI_CORE_LAYOUTDETAILS_H
 #define RMLUI_CORE_LAYOUTDETAILS_H
 
-#include "../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../Include/RmlUi/Core/StyleTypes.h"
 #include "../../Include/RmlUi/Core/Types.h"
 
 namespace Rml {

+ 6 - 5
Source/Core/LayoutEngine.cpp

@@ -27,15 +27,16 @@
  */
 
 #include "LayoutEngine.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../Include/RmlUi/Core/Element.h"
+#include "../../Include/RmlUi/Core/Profiling.h"
+#include "../../Include/RmlUi/Core/Types.h"
 #include "LayoutBlockBoxSpace.h"
 #include "LayoutDetails.h"
 #include "LayoutFlex.h"
 #include "LayoutInlineBoxText.h"
 #include "LayoutTable.h"
 #include "Pool.h"
-#include "../../Include/RmlUi/Core/Element.h"
-#include "../../Include/RmlUi/Core/Profiling.h"
-#include "../../Include/RmlUi/Core/Types.h"
 #include <cstddef>
 #include <float.h>
 
@@ -169,7 +170,7 @@ bool LayoutEngine::FormatElement(LayoutBlockBox* block_context_box, Element* ele
 
 	// 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.
-	if (computed.position == Style::Position::Absolute || computed.position == Style::Position::Fixed)
+	if (computed.position() == Style::Position::Absolute || computed.position() == Style::Position::Fixed)
 	{
 		if (uses_unsupported_display_position_float_combination("absolutely positioned"))
 			return true;
@@ -180,7 +181,7 @@ bool LayoutEngine::FormatElement(LayoutBlockBox* block_context_box, Element* ele
 	}
 
 	// If the element is floating, we remove it from the flow.
-	if (computed.float_ != Style::Float::None)
+	if (computed.float_() != Style::Float::None)
 	{
 		if (uses_unsupported_display_position_float_combination("floated"))
 			return true;

+ 17 - 16
Source/Core/LayoutFlex.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "LayoutFlex.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/ElementScroll.h"
 #include "../../Include/RmlUi/Core/Types.h"
@@ -178,12 +179,12 @@ void LayoutFlex::Format()
 	// For details, see https://drafts.csswg.org/css-flexbox/#layout-algorithm
 
 	const ComputedValues& computed_flex = element_flex->GetComputedValues();
-	const Style::FlexDirection direction = computed_flex.flex_direction;
+	const Style::FlexDirection direction = computed_flex.flex_direction();
 
 	const bool main_axis_horizontal = (direction == Style::FlexDirection::Row || direction == Style::FlexDirection::RowReverse);
 	const bool direction_reverse = (direction == Style::FlexDirection::RowReverse || direction == Style::FlexDirection::ColumnReverse);
-	const bool flex_single_line = (computed_flex.flex_wrap == Style::FlexWrap::Nowrap);
-	const bool wrap_reverse = (computed_flex.flex_wrap == Style::FlexWrap::WrapReverse);
+	const bool flex_single_line = (computed_flex.flex_wrap() == Style::FlexWrap::Nowrap);
+	const bool wrap_reverse = (computed_flex.flex_wrap() == Style::FlexWrap::WrapReverse);
 
 	const float main_available_size = (main_axis_horizontal ? flex_available_content_size.x : flex_available_content_size.y);
 	const float cross_available_size = (!main_axis_horizontal ? flex_available_content_size.x : flex_available_content_size.y);
@@ -209,11 +210,11 @@ void LayoutFlex::Format()
 		Element* element = element_flex->GetChild(i);
 		const ComputedValues& computed = element->GetComputedValues();
 
-		if (computed.display == Style::Display::None)
+		if (computed.display() == Style::Display::None)
 		{
 			continue;
 		}
-		else if (computed.position == Style::Position::Absolute || computed.position == Style::Position::Fixed)
+		else if (computed.position() == Style::Position::Absolute || computed.position() == Style::Position::Fixed)
 		{
 			absolutely_positioned_elements.push_back(element);
 			continue;
@@ -237,9 +238,9 @@ void LayoutFlex::Format()
 			item_main_size = computed_main_size.size;
 		}
 
-		item.flex_shrink_factor = computed.flex_shrink;
-		item.flex_grow_factor = computed.flex_grow;
-		item.align_self = computed.align_self;
+		item.flex_shrink_factor = computed.flex_shrink();
+		item.flex_grow_factor = computed.flex_grow();
+		item.align_self = computed.align_self();
 
 		static_assert(int(Style::AlignSelf::FlexStart) == int(Style::AlignItems::FlexStart) + 1 &&
 				int(Style::AlignSelf::Stretch) == int(Style::AlignItems::Stretch) + 1,
@@ -247,21 +248,21 @@ void LayoutFlex::Format()
 
 		// Use the container's align-items property if align-self is auto.
 		if (item.align_self == Style::AlignSelf::Auto)
-			item.align_self = static_cast<Style::AlignSelf>(static_cast<int>(computed_flex.align_items) + 1);
+			item.align_self = static_cast<Style::AlignSelf>(static_cast<int>(computed_flex.align_items()) + 1);
 
 		const float sum_padding_border = item.main.sum_edges - (item.main.margin_a + item.main.margin_b);
 
 		// Find the flex base size (possibly negative when using border box sizing)
-		if (computed.flex_basis.type != Style::FlexBasis::Auto)
+		if (computed.flex_basis().type != Style::FlexBasis::Auto)
 		{
-			item.inner_flex_base_size = ResolveValue(computed.flex_basis, main_size_base_value);
-			if (computed.box_sizing == Style::BoxSizing::BorderBox)
+			item.inner_flex_base_size = ResolveValue(computed.flex_basis(), main_size_base_value);
+			if (computed.box_sizing() == Style::BoxSizing::BorderBox)
 				item.inner_flex_base_size -= sum_padding_border;
 		}
 		else if (!item.main.auto_size)
 		{
 			item.inner_flex_base_size = ResolveValue(item_main_size, main_size_base_value);
-			if (computed.box_sizing == Style::BoxSizing::BorderBox)
+			if (computed.box_sizing() == Style::BoxSizing::BorderBox)
 				item.inner_flex_base_size -= sum_padding_border;
 		}
 		else if (main_axis_horizontal)
@@ -494,7 +495,7 @@ void LayoutFlex::Format()
 				using Style::JustifyContent;
 				const int num_items = int(line.items.size());
 
-				switch (computed_flex.justify_content)
+				switch (computed_flex.justify_content())
 				{
 				case JustifyContent::SpaceBetween:
 					if (num_items > 1)
@@ -610,7 +611,7 @@ void LayoutFlex::Format()
 	}
 
 	// Stretch out the lines if we have extra space.
-	if (cross_available_size >= 0.f && computed_flex.align_content == Style::AlignContent::Stretch)
+	if (cross_available_size >= 0.f && computed_flex.align_content() == Style::AlignContent::Stretch)
 	{
 		int remaining_space = static_cast<int>(cross_available_size -
 			std::accumulate(container.lines.begin(), container.lines.end(), 0.f,
@@ -757,7 +758,7 @@ void LayoutFlex::Format()
 		{
 			using Style::AlignContent;
 
-			switch (computed_flex.align_content)
+			switch (computed_flex.align_content())
 			{
 			case AlignContent::SpaceBetween:
 				if (num_lines > 1)

+ 4 - 3
Source/Core/LayoutInlineBox.cpp

@@ -27,13 +27,14 @@
  */
 
 #include "LayoutInlineBox.h"
-#include "LayoutBlockBox.h"
-#include "LayoutEngine.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Core.h"
 #include "../../Include/RmlUi/Core/ElementText.h"
 #include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../Include/RmlUi/Core/FontEngineInterface.h"
 #include "../../Include/RmlUi/Core/Property.h"
+#include "LayoutBlockBox.h"
+#include "LayoutEngine.h"
 
 namespace Rml {
 
@@ -68,7 +69,7 @@ LayoutInlineBox::LayoutInlineBox(Element* _element, const Box& _box) : position(
 		}
 	}
 
-	vertical_align_property = element->GetComputedValues().vertical_align;
+	vertical_align_property = element->GetComputedValues().vertical_align();
 
 	chained = false;
 	chain = nullptr;

+ 1 - 1
Source/Core/LayoutInlineBox.h

@@ -30,7 +30,7 @@
 #define RMLUI_CORE_LAYOUTINLINEBOX_H
 
 #include "../../Include/RmlUi/Core/Box.h"
-#include "../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../Include/RmlUi/Core/StyleTypes.h"
 
 namespace Rml {
 

+ 10 - 20
Source/Core/LayoutInlineBoxText.cpp

@@ -27,16 +27,17 @@
  */
 
 #include "LayoutInlineBoxText.h"
-#include "ComputeProperty.h"
-#include "LayoutEngine.h"
-#include "LayoutLineBox.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Core.h"
 #include "../../Include/RmlUi/Core/ElementText.h"
 #include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../Include/RmlUi/Core/FontEngineInterface.h"
 #include "../../Include/RmlUi/Core/Log.h"
-#include "../../Include/RmlUi/Core/Property.h"
 #include "../../Include/RmlUi/Core/Profiling.h"
+#include "../../Include/RmlUi/Core/Property.h"
+#include "ComputeProperty.h"
+#include "LayoutEngine.h"
+#include "LayoutLineBox.h"
 
 namespace Rml {
 
@@ -178,21 +179,9 @@ void LayoutInlineBoxText::BuildWordBox()
 		baseline = 0;
 
 		const ComputedValues& computed = text_element->GetComputedValues();
-		const String font_family_property = text_element->GetProperty<String>("font-family");
-		const String& font_family_computed = computed.font_family;
+		const String font_family_property = computed.font_family();
 
-		if (ComputeFontFamily(font_family_property) != font_family_computed)
-		{
-			Log::Message(
-				Log::LT_WARNING,
-				"No font face defined. Mismatch between specified font family property '%s' and computed value '%s'. "
-				"Make sure Context::Update is run after new elements are constructed, before Context::Render. On element %s",
-				font_family_property.c_str(),
-				font_family_computed.c_str(),
-				text_element->GetAddress().c_str()
-			);
-		}
-		else if (font_family_property.empty())
+		if (font_family_property.empty())
 		{
 			Log::Message(
 				Log::LT_WARNING,
@@ -202,11 +191,12 @@ void LayoutInlineBoxText::BuildWordBox()
 		}
 		else
 		{
-			const String font_face_description = FontFaceDescription(font_family_property, computed.font_style, computed.font_weight);
+			const String font_face_description = FontFaceDescription(font_family_property, computed.font_style(), computed.font_weight());
 
 			Log::Message(
 				Log::LT_WARNING,
-				"No font face defined. Ensure that the specified font face %s has been successfully loaded. "
+				"No font face defined. Ensure (1) that Context::Update is run after new elements are constructed, before Context::Render, "
+				"and (2) that the specified font face %s has been successfully loaded. "
 				"Please see previous log messages for all successfully loaded fonts. On element %s",
 				font_face_description.c_str(),
 				text_element->GetAddress().c_str()

+ 6 - 5
Source/Core/LayoutLineBox.cpp

@@ -27,13 +27,14 @@
  */
 
 #include "LayoutLineBox.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../Include/RmlUi/Core/ElementText.h"
+#include "../../Include/RmlUi/Core/ElementUtilities.h"
+#include "../../Include/RmlUi/Core/Profiling.h"
+#include "../../Include/RmlUi/Core/Property.h"
 #include "LayoutBlockBox.h"
 #include "LayoutEngine.h"
 #include "LayoutInlineBoxText.h"
-#include "../../Include/RmlUi/Core/Property.h"
-#include "../../Include/RmlUi/Core/ElementUtilities.h"
-#include "../../Include/RmlUi/Core/ElementText.h"
-#include "../../Include/RmlUi/Core/Profiling.h"
 #include <stack>
 
 namespace Rml {
@@ -138,7 +139,7 @@ LayoutInlineBox* LayoutLineBox::Close(UniquePtr<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.
-	Style::TextAlign text_align_property = parent->GetParent()->GetElement()->GetComputedValues().text_align;
+	Style::TextAlign text_align_property = parent->GetParent()->GetElement()->GetComputedValues().text_align();
 	if (text_align_property == Style::TextAlign::Center ||
 		text_align_property == Style::TextAlign::Right)
 	{

+ 11 - 10
Source/Core/LayoutTable.cpp

@@ -27,11 +27,12 @@
  */
 
 #include "LayoutTable.h"
-#include "LayoutTableDetails.h"
-#include "LayoutDetails.h"
-#include "LayoutEngine.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/Types.h"
+#include "LayoutDetails.h"
+#include "LayoutEngine.h"
+#include "LayoutTableDetails.h"
 #include <algorithm>
 #include <numeric>
 
@@ -42,8 +43,8 @@ Vector2f LayoutTable::FormatTable(Box& box, Vector2f min_size, Vector2f max_size
 	const ComputedValues& computed_table = element_table->GetComputedValues();
 
 	// Scrollbars are illegal in the table element.
-	if (!(computed_table.overflow_x == Style::Overflow::Visible || computed_table.overflow_x == Style::Overflow::Hidden) ||
-		!(computed_table.overflow_y == Style::Overflow::Visible || computed_table.overflow_y == Style::Overflow::Hidden))
+	if (!(computed_table.overflow_x() == Style::Overflow::Visible || computed_table.overflow_x() == Style::Overflow::Hidden) ||
+		!(computed_table.overflow_y() == Style::Overflow::Visible || computed_table.overflow_y() == Style::Overflow::Hidden))
 	{
 		Log::Message(Log::LT_WARNING, "Table elements can only have 'overflow' property values of 'visible' or 'hidden'. Table will not be formatted: %s.", element_table->GetAddress().c_str());
 		return Vector2f(0);
@@ -58,14 +59,14 @@ Vector2f LayoutTable::FormatTable(Box& box, Vector2f min_size, Vector2f max_size
 	Math::SnapToPixelGrid(table_content_offset, table_initial_content_size);
 
 	// When width or height is set, they act as minimum width or height, just as in CSS.
-	if (computed_table.width.type != Style::Width::Auto)
+	if (computed_table.width().type != Style::Width::Auto)
 		min_size.x = Math::Max(min_size.x, table_initial_content_size.x);
-	if (computed_table.height.type != Style::Height::Auto)
+	if (computed_table.height().type != Style::Height::Auto)
 		min_size.y = Math::Max(min_size.y, table_initial_content_size.y);
 
 	const Vector2f table_gap = Vector2f(
-		ResolveValue(computed_table.column_gap, table_initial_content_size.x), 
-		ResolveValue(computed_table.row_gap, table_initial_content_size.y)
+		ResolveValue(computed_table.column_gap(), table_initial_content_size.x), 
+		ResolveValue(computed_table.row_gap(), table_initial_content_size.y)
 	);
 
 	TableGrid grid;
@@ -387,7 +388,7 @@ void LayoutTable::FormatCells()
 		Element* element_cell = grid_cell.element_cell;
 
 		Box& box = cells[cell_index];
-		Style::VerticalAlign vertical_align = element_cell->GetComputedValues().vertical_align;
+		Style::VerticalAlign vertical_align = element_cell->GetComputedValues().vertical_align();
 
 		const float cell_border_height = GetSpanningCellBorderSize(rows, grid_cell.row_begin, grid_cell.row_last);
 		const Vector2f cell_offset = table_content_offset + Vector2f(

+ 3 - 2
Source/Core/LayoutTableDetails.cpp

@@ -27,8 +27,9 @@
  */
 
 #include "LayoutTableDetails.h"
-#include "LayoutDetails.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
+#include "LayoutDetails.h"
 #include <algorithm>
 #include <float.h>
 
@@ -220,7 +221,7 @@ void TableGrid::PushRow(Element* element_row, ElementList cell_elements)
 		{
 			Element* element_cell = element_row->GetChild(j);
 
-			const Style::Display cell_display = element_cell->GetComputedValues().display;
+			const Style::Display cell_display = element_cell->GetComputedValues().display();
 			if (cell_display == Style::Display::TableCell)
 			{
 				cell_elements.push_back(element_cell);

+ 1 - 1
Source/Core/LayoutTableDetails.h

@@ -30,7 +30,7 @@
 #define RMLUI_CORE_LAYOUTTABLEDETAILS_H
 
 #include "../../Include/RmlUi/Core/Types.h"
-#include "../../Include/RmlUi/Core/ComputedValues.h"
+#include "../../Include/RmlUi/Core/StyleTypes.h"
 #include <float.h>
 
 namespace Rml {

+ 3 - 2
Source/Core/StyleSheetContainer.cpp

@@ -27,9 +27,10 @@
  */
 
 #include "../../Include/RmlUi/Core/StyleSheetContainer.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Context.h"
-#include "../../Include/RmlUi/Core/PropertyDictionary.h"
 #include "../../Include/RmlUi/Core/Profiling.h"
+#include "../../Include/RmlUi/Core/PropertyDictionary.h"
 #include "../../Include/RmlUi/Core/StyleSheet.h"
 #include "../../Include/RmlUi/Core/Utilities.h"
 #include "ComputeProperty.h"
@@ -62,7 +63,7 @@ bool StyleSheetContainer::UpdateCompiledStyleSheet(const Context* context)
 
 	Vector<int> new_active_media_block_indices;
 
-	const float font_size = DefaultComputedValues.font_size;
+	const float font_size = DefaultComputedValues.font_size();
 
 	for (int media_block_index = 0; media_block_index < (int)media_blocks.size(); media_block_index++)
 	{

+ 9 - 8
Source/Core/WidgetScroll.cpp

@@ -27,12 +27,13 @@
  */
 
 #include "WidgetScroll.h"
-#include "Clock.h"
-#include "LayoutDetails.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/Event.h"
 #include "../../Include/RmlUi/Core/Factory.h"
 #include "../../Include/RmlUi/Core/Property.h"
+#include "Clock.h"
+#include "LayoutDetails.h"
 
 namespace Rml {
 
@@ -301,8 +302,8 @@ void WidgetScroll::FormatBar(float bar_length)
 
 	const auto& computed = bar->GetComputedValues();
 
-	const Style::Width width = computed.width;
-	const Style::Height height = computed.height;
+	const Style::Width width = computed.width();
+	const Style::Height height = computed.height();
 
 	Vector2f bar_box_content = bar_box.GetSize();
 	if (orientation == HORIZONTAL)
@@ -324,11 +325,11 @@ void WidgetScroll::FormatBar(float bar_length)
 				bar_box_content.y = track_length * bar_length;
 
 				// Check for 'min-height' restrictions.
-				float min_track_length = ResolveValue(computed.min_height, track_length);
+				float min_track_length = ResolveValue(computed.min_height(), track_length);
 				bar_box_content.y = Math::Max(min_track_length, bar_box_content.y);
 
 				// Check for 'max-height' restrictions.
-				float max_track_length = ResolveValue(computed.max_height, track_length);
+				float max_track_length = ResolveValue(computed.max_height(), track_length);
 				if (max_track_length > 0)
 					bar_box_content.y = Math::Min(max_track_length, bar_box_content.y);
 			}
@@ -345,11 +346,11 @@ void WidgetScroll::FormatBar(float bar_length)
 				bar_box_content.x = track_length * bar_length;
 
 				// Check for 'min-width' restrictions.
-				float min_track_length = ResolveValue(computed.min_width, track_length);
+				float min_track_length = ResolveValue(computed.min_width(), track_length);
 				bar_box_content.x = Math::Max(min_track_length, bar_box_content.x);
 
 				// Check for 'max-width' restrictions.
-				float max_track_length = ResolveValue(computed.max_width, track_length);
+				float max_track_length = ResolveValue(computed.max_width(), track_length);
 				if (max_track_length > 0)
 					bar_box_content.x = Math::Min(max_track_length, bar_box_content.x);
 			}

+ 6 - 5
Source/Lottie/ElementLottie.cpp

@@ -27,12 +27,13 @@
  */
 
 #include "../../Include/RmlUi/Lottie/ElementLottie.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Core.h"
-#include "../../Include/RmlUi/Core/PropertyIdSet.h"
-#include "../../Include/RmlUi/Core/GeometryUtilities.h"
 #include "../../Include/RmlUi/Core/ElementDocument.h"
-#include "../../Include/RmlUi/Core/SystemInterface.h"
 #include "../../Include/RmlUi/Core/FileInterface.h"
+#include "../../Include/RmlUi/Core/GeometryUtilities.h"
+#include "../../Include/RmlUi/Core/PropertyIdSet.h"
+#include "../../Include/RmlUi/Core/SystemInterface.h"
 #include <cmath>
 #include <rlottie.h>
 
@@ -115,8 +116,8 @@ void ElementLottie::GenerateGeometry()
 
 	const ComputedValues& computed = GetComputedValues();
 
-	const float opacity = computed.opacity;
-	Colourb quad_colour = computed.image_color;
+	const float opacity = computed.opacity();
+	Colourb quad_colour = computed.image_color();
 	quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha);
 
 	const Vector2f render_dimensions_f = GetBox().GetSize(Box::CONTENT).Round();

+ 6 - 5
Source/SVG/ElementSVG.cpp

@@ -27,13 +27,14 @@
  */
 
 #include "../../Include/RmlUi/SVG/ElementSVG.h"
+#include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Core.h"
-#include "../../Include/RmlUi/Core/PropertyIdSet.h"
-#include "../../Include/RmlUi/Core/GeometryUtilities.h"
 #include "../../Include/RmlUi/Core/ElementDocument.h"
-#include "../../Include/RmlUi/Core/SystemInterface.h"
 #include "../../Include/RmlUi/Core/FileInterface.h"
+#include "../../Include/RmlUi/Core/GeometryUtilities.h"
 #include "../../Include/RmlUi/Core/Math.h"
+#include "../../Include/RmlUi/Core/PropertyIdSet.h"
+#include "../../Include/RmlUi/Core/SystemInterface.h"
 #include <cmath>
 #include <lunasvg.h>
 
@@ -130,8 +131,8 @@ void ElementSVG::GenerateGeometry()
 
 	const ComputedValues& computed = GetComputedValues();
 
-	const float opacity = computed.opacity;
-	Colourb quad_colour = computed.image_color;
+	const float opacity = computed.opacity();
+	Colourb quad_colour = computed.image_color();
 	quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha);
 
 	const Vector2f render_dimensions_f = GetBox().GetSize(Box::CONTENT).Round();