Browse Source

Merge remote-tracking branch 'origin/master' into performance

# Conflicts:
#	Include/Rocket/Core/TransformPrimitive.h
#	Include/Rocket/Core/Types.h
#	Source/Core/Context.cpp
#	Source/Core/Element.cpp
#	Source/Core/ElementAnimation.cpp
#	readme.md
Michael Ragazzon 6 years ago
parent
commit
90c2d5005e
59 changed files with 686 additions and 328 deletions
  1. 28 0
      .appveyor.yml
  2. 66 0
      .travis.yml
  3. 30 20
      Build/CMakeLists.txt
  4. 4 0
      Include/Rocket/Core/Animation.h
  5. 3 2
      Include/Rocket/Core/Context.h
  6. 6 3
      Include/Rocket/Core/Dictionary.h
  7. 0 5
      Include/Rocket/Core/Header.h
  8. 3 3
      Include/Rocket/Core/Lua/lua.hpp
  9. 4 0
      Include/Rocket/Core/Math.h
  10. 0 1
      Include/Rocket/Core/Matrix4.inl
  11. 0 1
      Include/Rocket/Core/StringUtilities.h
  12. 4 4
      Include/Rocket/Core/Transform.h
  13. 87 87
      Include/Rocket/Core/TransformPrimitive.h
  14. 5 4
      Include/Rocket/Core/Tween.h
  15. 4 1
      Include/Rocket/Core/TypeConverter.inl
  16. 1 1
      Include/Rocket/Core/Types.h
  17. 2 2
      Include/Rocket/Core/Vector2.inl
  18. 4 2
      Include/Rocket/Core/Vector3.inl
  19. 3 1
      Include/Rocket/Core/Vector4.inl
  20. 22 0
      LICENSE
  21. 0 1
      Samples/basic/animation/src/main.cpp
  22. 1 1
      Samples/basic/drag/data/icon.rcss
  23. 1 1
      Samples/basic/sdl2/src/SystemInterfaceSDL2.cpp
  24. 1 1
      Samples/basic/sdl2/src/SystemInterfaceSDL2.h
  25. 1 1
      Samples/luainvaders/data/game.rml
  26. 1 1
      Samples/luainvaders/data/start_game.rml
  27. 5 0
      Samples/shell/include/ShellOpenGL.h
  28. 3 3
      Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp
  29. 2 2
      Samples/shell/src/x11/ShellX11.cpp
  30. 2 2
      Samples/tutorial/datagrid/data/tutorial.rcss
  31. 2 2
      Samples/tutorial/datagrid_tree/data/tutorial.rcss
  32. 1 1
      Samples/tutorial/template/data/tutorial.rcss
  33. 1 1
      Samples/tutorial/tutorial_drag/data/tutorial.rcss
  34. 2 2
      Source/Core/BitmapFont/FontFaceLayer.h
  35. 1 1
      Source/Core/Clock.cpp
  36. 1 1
      Source/Core/Clock.h
  37. 1 1
      Source/Core/ComputeProperty.cpp
  38. 11 5
      Source/Core/Context.cpp
  39. 16 11
      Source/Core/Element.cpp
  40. 13 32
      Source/Core/ElementAnimation.cpp
  41. 2 1
      Source/Core/ElementStyle.cpp
  42. 1 1
      Source/Core/ElementTextDefault.cpp
  43. 4 4
      Source/Core/ElementUtilities.cpp
  44. 1 1
      Source/Core/FontFaceLayer.h
  45. 1 0
      Source/Core/FreeType/FontProvider.cpp
  46. 0 40
      Source/Core/Lua/Context.cpp
  47. 0 5
      Source/Core/Lua/Context.h
  48. 6 0
      Source/Core/Math.cpp
  49. 4 2
      Source/Core/PropertyParserAnimation.cpp
  50. 1 1
      Source/Core/PropertyParserTransform.cpp
  51. 1 0
      Source/Core/String.cpp
  52. 2 1
      Source/Core/StyleSheetNode.cpp
  53. 1 1
      Source/Core/StyleSheetSpecification.cpp
  54. 2 1
      Source/Core/Transform.cpp
  55. 279 29
      Source/Core/TransformPrimitive.cpp
  56. 0 1
      Source/Core/TransformState.cpp
  57. 0 1
      Source/Core/ViewState.cpp
  58. 3 1
      Source/Debugger/ElementInfo.cpp
  59. 36 31
      readme.md

+ 28 - 0
.appveyor.yml

@@ -0,0 +1,28 @@
+version: 1.0.{build}
+image: Visual Studio 2017
+environment:
+  matrix:
+  - FREETYPE_VER: 2.10.0
+    VS_GENERATOR: Visual Studio 15 2017 Win64
+    BUILD_SHARED_LIBS: ON
+    BUILD_SAMPLES: ON
+  - FREETYPE_VER: 2.10.0
+    VS_GENERATOR: Visual Studio 15 2017 Win64
+    BUILD_SHARED_LIBS: OFF
+    BUILD_SAMPLES: OFF
+install:
+- cmd: >-
+    cd Dependencies
+
+    appveyor DownloadFile https://github.com/ubawurinna/freetype-windows-binaries/releases/download/v2.10.0/freetype-%FREETYPE_VER%.zip
+
+    unzip -o freetype-%FREETYPE_VER%.zip
+
+    mv win64 lib
+
+    cd ../Build
+
+    cmake -G "%VS_GENERATOR%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% -DBUILD_SAMPLES=%BUILD_SAMPLES% -DSKIP_DIRECTX_SAMPLES=ON .
+build:
+  parallel: true
+  verbosity: minimal

+ 66 - 0
.travis.yml

@@ -0,0 +1,66 @@
+sudo: false
+dist: trusty
+
+matrix:
+  include:
+    - os: osx
+      osx_image: xcode10.2
+      env: ARCH=OSX
+      language: c++
+      compiler: clang
+    - os: linux
+      language: c++
+      compiler: clang
+      env: MATRIX_EVAL="CC=clang-6.0 CXX=clang++-6.0"
+      addons:
+        apt:
+          sources:
+            - ubuntu-toolchain-r-test
+            - llvm-toolchain-trusty-6.0
+          packages:
+            - clang-6.0
+            - libstdc++-7-dev
+            - cmake
+            - build-essential
+            - libboost-dev
+            - libboost-python-dev
+            - libsdl2-dev
+            - libsdl2-image-dev
+            - libfreetype6-dev
+            - libglew-dev
+            - liblua5.2-dev
+            - libsfml-dev
+    - os: linux
+      language: c++
+      compiler: gcc
+      env: MATRIX_EVAL="CC=gcc-7 CXX=g++-7"
+      addons:
+        apt:
+          sources:
+            - ubuntu-toolchain-r-test
+          packages:
+            - g++-7
+            - cmake
+            - build-essential
+            - libboost-dev
+            - libboost-python-dev
+            - libsdl2-dev
+            - libsdl2-image-dev
+            - libfreetype6-dev
+            - libglew-dev
+            - liblua5.2-dev
+            - libsfml-dev
+
+before_install:
+  - if [[ -n "${MATRIX_EVAL}" ]]; then eval "${MATRIX_EVAL}" ; fi
+
+install:
+  - cd "$TRAVIS_BUILD_DIR/Build"
+  - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then cmake -DBUILD_LUA_BINDINGS=ON -DBUILD_SAMPLES=ON .; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cmake -G Xcode .; fi
+  - cd "$TRAVIS_BUILD_DIR"
+
+script:
+  - cd Build
+  - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then make -j4; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project librocket.xcodeproj/ -jobs 4 -configuration Release -target ALL_BUILD; fi

+ 30 - 20
Build/CMakeLists.txt

@@ -17,13 +17,13 @@ if(APPLE)
 				set (IOS_ARCH armv6 armv7 armv7s arm64)
 				set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string  "Build architecture for iOS")
 			else (${IOS_PLATFORM} STREQUAL "OS")
-				set (IOS_ARCH i386 x86_64)
+				set (IOS_ARCH x86_64)
 				set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string  "Build architecture for iOS Simulator")
 			endif (${IOS_PLATFORM} STREQUAL "OS")
 
 		else(IOS)
 			# set the architectures for OS X
-			set (OSXI_ARCH i386 x86_64)
+			set (OSXI_ARCH x86_64)
 			set (CMAKE_OSX_ARCHITECTURES ${OSXI_ARCH} CACHE string  "Build architecture for OS X universal binaries")		
 		endif(IOS)
 	endif (NOT CMAKE_OSX_ARCHITECTURES AND BUILD_UNIVERSAL_BINARIES)
@@ -269,7 +269,7 @@ foreach(library ${LIBRARIES})
 		target_compile_options(${NAME} PUBLIC "/MP")
 	endif(MSVC)
 	
-	set_property(TARGET ${NAME} PROPERTY CXX_STANDARD 17)
+	set_property(TARGET ${NAME} PROPERTY CXX_STANDARD 11)
 	set_property(TARGET ${NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
     
     install(TARGETS ${NAME}
@@ -368,6 +368,9 @@ if(BUILD_PYTHON_BINDINGS)
 
         set_target_properties(${NAME} PROPERTIES PREFIX "")
 
+        set_property(TARGET ${NAME} PROPERTY CXX_STANDARD 11)
+        set_property(TARGET ${NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
+
         install(TARGETS ${NAME}
                 EXPORT libRocketTargets
                 LIBRARY DESTINATION ${PYTHON_INSTDIR}
@@ -392,7 +395,10 @@ if(BUILD_LUA_BINDINGS)
                            VERSION ${PROJECT_VERSION}
                            SOVERSION ${LIBROCKET_VERSION_MAJOR}
         )
-        
+
+        set_property(TARGET ${NAME} PROPERTY CXX_STANDARD 11)
+        set_property(TARGET ${NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
+
         install(TARGETS ${NAME}
             EXPORT libRocketTargets
             LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
@@ -459,11 +465,6 @@ endif()
     else()
     	add_executable(${NAME} ${${NAME}_SRC_FILES} ${${NAME}_HDR_FILES} )
     endif()
-    
-    if (APPLE)
-    	# We only support i386 for the samples as it still uses Carbon
-    	set_target_properties(${NAME} PROPERTIES OSX_ARCHITECTURES "i386;" )
-    endif()
 
     target_link_libraries(${NAME} ${ARGN})
 endmacro()
@@ -586,18 +587,14 @@ endif(NOT BUILD_FRAMEWORK)
 
     # Build and install sample shell library
     add_library(shell STATIC ${shell_SRC_FILES} ${shell_HDR_FILES})
-	set_property(TARGET shell PROPERTY CXX_STANDARD 17)
+	set_property(TARGET shell PROPERTY CXX_STANDARD 11)
 	set_property(TARGET shell PROPERTY CXX_STANDARD_REQUIRED ON)
-    if (APPLE)
-    	# We only support i386 for the samples as it still uses Carbon
-    	set_target_properties(shell PROPERTIES OSX_ARCHITECTURES "i386;")
-    endif()
 
     # Build and install the basic samples
     foreach(sample ${samples})
         bl_sample(${sample} ${sample_LIBRARIES})
 		
-		set_property(TARGET ${sample} PROPERTY CXX_STANDARD 17)
+		set_property(TARGET ${sample} PROPERTY CXX_STANDARD 11)
 		set_property(TARGET ${sample} PROPERTY CXX_STANDARD_REQUIRED ON)
 
         # The samples always set this as their current working directory
@@ -644,6 +641,9 @@ endif(NOT BUILD_FRAMEWORK)
 			include_directories(${SDL2_INCLUDE_DIR} ${GLEW_INCLUDE_DIR})
 
 			bl_sample(sdl2 ${sample_LIBRARIES}  ${SDL2_LIBRARY} ${SDL2_IMAGE_LIBRARY} ${GLEW_LIBRARY})
+			set_property(TARGET sdl2 PROPERTY CXX_STANDARD 11)
+			set_property(TARGET sdl2 PROPERTY CXX_STANDARD_REQUIRED ON)
+		
 			# The samples always set this as their current working directory
 			install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/sdl2)
 			install(TARGETS sdl2
@@ -680,7 +680,11 @@ endif(NOT BUILD_FRAMEWORK)
 	endif()
 
 	message("-- Can SFML 2.x sample be built")
-	find_package(SFML 2 COMPONENTS graphics window system main)
+	if (WIN32)
+		find_package(SFML 2 COMPONENTS graphics window system main)
+	else()
+		find_package(SFML 2 COMPONENTS graphics window system)
+	endif()
 	if(NOT SFML_FOUND)
 		message("-- Can SFML 2.x sample be built - no")
 	else()
@@ -695,7 +699,10 @@ endif(NOT BUILD_FRAMEWORK)
 			include_directories(${SFML_INCLUDE_DIR})
 			bl_sample(sfml2 ${sample_LIBRARIES} ${SFML_LIBRARIES})
 		endif()
-
+		
+			set_property(TARGET sfml2 PROPERTY CXX_STANDARD 11)
+			set_property(TARGET sfml2 PROPERTY CXX_STANDARD_REQUIRED ON)
+			
 			# The samples always set this as their current working directory
 			install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/sfml2)
 			install(TARGETS sfml2
@@ -710,6 +717,9 @@ endif(NOT BUILD_FRAMEWORK)
 		set_property(TARGET ${tutorial} PROPERTY CXX_STANDARD 17)
 		set_property(TARGET ${tutorial} PROPERTY CXX_STANDARD_REQUIRED ON)
 
+		set_property(TARGET ${tutorial} PROPERTY CXX_STANDARD 11)
+		set_property(TARGET ${tutorial} PROPERTY CXX_STANDARD_REQUIRED ON)
+		
         # The tutorials always set this as their current working directory
         install(DIRECTORY DESTINATION ${SAMPLES_DIR}/tutorial/${tutorial})
         install(TARGETS ${tutorial}
@@ -719,7 +729,7 @@ endif(NOT BUILD_FRAMEWORK)
 
     # Build and install invaders sample
     bl_sample(invaders ${sample_LIBRARIES})
-	set_property(TARGET invaders PROPERTY CXX_STANDARD 17)
+	set_property(TARGET invaders PROPERTY CXX_STANDARD 11)
 	set_property(TARGET invaders PROPERTY CXX_STANDARD_REQUIRED ON)
     install(DIRECTORY DESTINATION ${SAMPLES_DIR}/invaders)
     install(TARGETS invaders 
@@ -729,7 +739,7 @@ endif(NOT BUILD_FRAMEWORK)
 	if(BUILD_PYTHON_BINDINGS)
 	    # Build and install pyinvaders sample
 	    bl_sample(pyinvaders ${sample_LIBRARIES} ${PYTHON_LIBRARIES} ${PY_BINDINGS_LINK_LIBS})
-		set_property(TARGET pyinvaders PROPERTY CXX_STANDARD 17)
+		set_property(TARGET pyinvaders PROPERTY CXX_STANDARD 11)
 		set_property(TARGET pyinvaders PROPERTY CXX_STANDARD_REQUIRED ON)
 	    install(DIRECTORY DESTINATION ${SAMPLES_DIR}/pyinvaders)
 	    install(TARGETS pyinvaders
@@ -739,7 +749,7 @@ endif(NOT BUILD_FRAMEWORK)
     
     if(BUILD_LUA_BINDINGS)
         bl_sample(luainvaders RocketCoreLua RocketControlsLua ${sample_LIBRARIES} ${LUA_BINDINGS_LINK_LIBS})
-		set_property(TARGET luainvaders PROPERTY CXX_STANDARD 17)
+		set_property(TARGET luainvaders PROPERTY CXX_STANDARD 11)
 		set_property(TARGET luainvaders PROPERTY CXX_STANDARD_REQUIRED ON)
         install(DIRECTORY DESTINATION ${SAMPLES_DIR}/luainvaders)
         install(TARGETS luainvaders 

+ 4 - 0
Include/Rocket/Core/Animation.h

@@ -63,6 +63,10 @@ struct TransitionList {
 	bool none = true;
 	bool all = false;
 	std::vector<Transition> transitions;
+
+	TransitionList() {}
+	TransitionList(bool none, bool all, std::vector<Transition> transitions) :
+		none(none), all(all), transitions(transitions) {}
 };
 
 inline bool operator==(const Animation& a, const Animation& b) { return a.duration == b.duration && a.tween == b.tween && a.delay == b.delay && a.alternate == b.alternate && a.paused == b.paused && a.num_iterations == b.num_iterations && a.name == b.name; }

+ 3 - 2
Include/Rocket/Core/Context.h

@@ -118,8 +118,8 @@ public:
 	/// Unloads all loaded documents.
 	void UnloadAllDocuments();
 
-	/// Enable or disable handling mouse cursor from this context.
-	/// Only a single context should handle the mouse cursor at the same time.
+	/// Enable or disable handling of the mouse cursor from this context.
+	/// When enabled, changes to the cursor name is transmitted through the system interface.
 	/// @param[in] show True to enable mouse cursor handling, false to disable.
 	void EnableMouseCursor(bool enable);
 
@@ -265,6 +265,7 @@ private:
 
 	// Enables cursor handling.
 	bool enable_cursor;
+	String cursor_name;
 	// Document attached to cursor (e.g. while dragging).
 	ElementDocument* cursor_proxy;
 

+ 6 - 3
Include/Rocket/Core/Dictionary.h

@@ -36,13 +36,15 @@ namespace Core {
 
 inline Variant* GetIf(Dictionary& dictionary, const String& key)
 {
-	if (auto it = dictionary.find(key); it != dictionary.end())
+	auto it = dictionary.find(key);
+	if (it != dictionary.end())
 		return &(it->second);
 	return nullptr;
 }
 inline const Variant* GetIf(const Dictionary& dictionary, const String& key)
 {
-	if (auto it = dictionary.find(key); it != dictionary.end())
+	auto it = dictionary.find(key);
+	if (it != dictionary.end())
 		return &(it->second);
 	return nullptr;
 }
@@ -50,7 +52,8 @@ template<typename T>
 inline T Get(const Dictionary& dictionary, const String& key, const T& default_value)
 {
 	T result = default_value;
-	if (auto it = dictionary.find(key); it != dictionary.end())
+	auto it = dictionary.find(key);
+	if (it != dictionary.end())
 		it->second.GetInto(result);
 	return result;
 }

+ 0 - 5
Include/Rocket/Core/Header.h

@@ -33,11 +33,6 @@
 // Note: Changing a ROCKETCORE_API_INLINE method
 // breaks ABI compatibility!!
 
-#ifdef STATIC_LIB
-	#define ROCKET_STATIC_LIB
-	#pragma message("DEPRECATED: STATIC_LIB macro has been deprecated in favor of ROCKET_STATIC_LIB and support will be removed in a future release")
-#endif
-
 #if !defined ROCKET_STATIC_LIB
 	#if defined ROCKET_PLATFORM_WIN32
 		#if defined RocketCore_EXPORTS

+ 3 - 3
Include/Rocket/Core/Lua/lua.hpp

@@ -28,7 +28,7 @@
 //The standard Lua headers
 
 extern "C" {
-#include "lua.h"
-#include "lauxlib.h"
-#include "lualib.h"
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
 }

+ 4 - 0
Include/Rocket/Core/Math.h

@@ -108,6 +108,10 @@ ROCKETCORE_API float Tan(float angle);
 /// @param[in] x The x-component of the line.
 /// @return The angle of the line in radians.
 ROCKETCORE_API float ATan2(float y, float x);
+/// Evaluates the natural exponential function on a value.
+/// @param[in] value The value
+/// @return e^(value)
+ROCKETCORE_API float Exp(float value);
 
 /// Converts an angle from radians to degrees.
 /// @param[in] The angle, in radians.

+ 0 - 1
Include/Rocket/Core/Matrix4.inl

@@ -68,7 +68,6 @@ Matrix4< Component, Storage >::Matrix4(const typename Matrix4< Component, Storag
 	{
 		rows[i] = other_rows[i];
 	}
-	return *this;
 }
 
 // Assignment operator

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

@@ -31,7 +31,6 @@
 #include "Header.h"
 #include "Types.h"
 #include "String.h"
-#include <stdarg.h>
 
 namespace Rocket {
 namespace Core {

+ 4 - 4
Include/Rocket/Core/Transform.h

@@ -29,12 +29,11 @@
 #define ROCKETCORETRANSFORM_H
 
 #include "Header.h"
-#include "ReferenceCountable.h"
+#include "TransformPrimitive.h"
 
 namespace Rocket {
 namespace Core {
 
-namespace Transforms { struct Primitive; }
 class Property;
 
 /**
@@ -77,12 +76,13 @@ public:
 	Primitives& GetPrimitives() noexcept { return primitives; }
 	const Primitives& GetPrimitives() const noexcept { return primitives; }
 
-	String ToString() const;
-
 private:
 	Primitives primitives;
 };
 
+
+ROCKETCORE_API String ToString(const Transform& transform);
+
 }
 }
 

+ 87 - 87
Include/Rocket/Core/TransformPrimitive.h

@@ -31,15 +31,15 @@
 #include "Header.h"
 #include "Types.h"
 #include "Property.h"
-#include <variant>
 #include <array>
 
+
 namespace Rocket {
 namespace Core {
 namespace Transforms {
 	
 
-struct NumericValue
+struct ROCKETCORE_API NumericValue
 {
 	/// Non-initializing constructor.
 	NumericValue() noexcept;
@@ -91,8 +91,6 @@ struct ResolvedPrimitive
 	ResolvedPrimitive(std::array<float, N> values) noexcept : values(values) { }
 	
 	std::array<float, N> values;
-
-	String ToString(String unit, bool rad_to_deg = false, bool only_unit_on_last_value = false) const noexcept;
 };
 
 template< size_t N >
@@ -106,162 +104,139 @@ struct UnresolvedPrimitive
 	UnresolvedPrimitive(std::array<NumericValue, N> values) noexcept : values(values) { }
 
 	std::array<NumericValue, N> values;
-
-	String ToString() const noexcept;
 };
 
 
 
 
 
-struct Matrix2D : public ResolvedPrimitive< 6 >
+struct ROCKETCORE_API Matrix2D : public ResolvedPrimitive< 6 >
 {
 	Matrix2D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
-	String ToString() const noexcept { return "matrix" + ResolvedPrimitive< 6 >::ToString(""); }
 };
 
-struct Matrix3D : public ResolvedPrimitive< 16 >
+struct ROCKETCORE_API Matrix3D : public ResolvedPrimitive< 16 >
 {
-	Matrix3D(const Matrix4f& matrix) noexcept : ResolvedPrimitive(matrix.data()) { }
 	Matrix3D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
-	String ToString() const noexcept { return "matrix3d" + ResolvedPrimitive< 16 >::ToString(""); }
+	Matrix3D(const Matrix4f& matrix) noexcept : ResolvedPrimitive(matrix.data()) { }
 };
 
-struct TranslateX : public UnresolvedPrimitive< 1 >
+struct ROCKETCORE_API TranslateX : public UnresolvedPrimitive< 1 >
 {
 	TranslateX(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
 	TranslateX(float x, Property::Unit unit = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(x, unit) }) { }
-	String ToString() const noexcept { return "translateX" + UnresolvedPrimitive< 1 >::ToString(); }
 };
 
-struct TranslateY : public UnresolvedPrimitive< 1 >
+struct ROCKETCORE_API TranslateY : public UnresolvedPrimitive< 1 >
 {
 	TranslateY(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
 	TranslateY(float y, Property::Unit unit = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(y, unit) }) { }
-	String ToString() const noexcept { return "translateY" + UnresolvedPrimitive< 1 >::ToString(); }
 };
 
-struct TranslateZ : public UnresolvedPrimitive< 1 >
+struct ROCKETCORE_API TranslateZ : public UnresolvedPrimitive< 1 >
 {
 	TranslateZ(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
 	TranslateZ(float z, Property::Unit unit = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(z, unit) }) { }
-	String ToString() const noexcept { return "translateZ" + UnresolvedPrimitive< 1 >::ToString(); }
 };
 
-struct Translate2D : public UnresolvedPrimitive< 2 >
+struct ROCKETCORE_API Translate2D : public UnresolvedPrimitive< 2 >
 {
 	Translate2D(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
 	Translate2D(float x, float y, Property::Unit units = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(x, units), NumericValue(y, units) }) { }
-	String ToString() const noexcept { return "translate" + UnresolvedPrimitive< 2 >::ToString(); }
 };
 
-struct Translate3D : public UnresolvedPrimitive< 3 >
+struct ROCKETCORE_API Translate3D : public UnresolvedPrimitive< 3 >
 {
 	Translate3D(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
 	Translate3D(NumericValue x, NumericValue y, NumericValue z) noexcept : UnresolvedPrimitive({ x, y, z }) { }
 	Translate3D(float x, float y, float z, Property::Unit units = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(x, units), NumericValue(y, units), NumericValue(z, units) }) { }
-	String ToString() const noexcept { return "translate3d" + UnresolvedPrimitive< 3 >::ToString(); }
 };
 
-struct ScaleX : public ResolvedPrimitive< 1 >
+struct ROCKETCORE_API ScaleX : public ResolvedPrimitive< 1 >
 {
 	ScaleX(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
 	ScaleX(float value) noexcept : ResolvedPrimitive({ value }) { }
-	String ToString() const noexcept { return "scaleX" + ResolvedPrimitive< 1 >::ToString(""); }
 };
 
-struct ScaleY : public ResolvedPrimitive< 1 >
+struct ROCKETCORE_API ScaleY : public ResolvedPrimitive< 1 >
 {
 	ScaleY(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
 	ScaleY(float value) noexcept : ResolvedPrimitive({ value }) { }
-	String ToString() const noexcept { return "scaleY" + ResolvedPrimitive< 1 >::ToString(""); }
 };
 
-struct ScaleZ : public ResolvedPrimitive< 1 >
+struct ROCKETCORE_API ScaleZ : public ResolvedPrimitive< 1 >
 {
 	ScaleZ(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
 	ScaleZ(float value) noexcept : ResolvedPrimitive({ value }) { }
-	String ToString() const noexcept { return "scaleZ" + ResolvedPrimitive< 1 >::ToString(""); }
 };
 
-struct Scale2D : public ResolvedPrimitive< 2 >
+struct ROCKETCORE_API Scale2D : public ResolvedPrimitive< 2 >
 {
 	Scale2D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
 	Scale2D(float xy) noexcept : ResolvedPrimitive({ xy, xy }) { }
 	Scale2D(float x, float y) noexcept : ResolvedPrimitive({ x, y }) { }
-	String ToString() const noexcept { return "scale" + ResolvedPrimitive< 2 >::ToString(""); }
 };
 
-struct Scale3D : public ResolvedPrimitive< 3 >
+struct ROCKETCORE_API Scale3D : public ResolvedPrimitive< 3 >
 {
 	Scale3D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
 	Scale3D(float xyz) noexcept : ResolvedPrimitive({ xyz, xyz, xyz }) { }
 	Scale3D(float x, float y, float z) noexcept : ResolvedPrimitive({ x, y, z }) { }
-	String ToString() const noexcept { return "scale3d" + ResolvedPrimitive< 3 >::ToString(""); }
 };
 
-struct RotateX : public ResolvedPrimitive< 1 >
+struct ROCKETCORE_API RotateX : public ResolvedPrimitive< 1 >
 {
 	RotateX(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
 	RotateX(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
-	String ToString() const noexcept { return "rotateX" + ResolvedPrimitive< 1 >::ToString("deg", true); }
 };
 
-struct RotateY : public ResolvedPrimitive< 1 >
+struct ROCKETCORE_API RotateY : public ResolvedPrimitive< 1 >
 {
 	RotateY(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) {}
 	RotateY(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
-	String ToString() const noexcept { return "rotateY" + ResolvedPrimitive< 1 >::ToString("deg", true); }
 };
 
-struct RotateZ : public ResolvedPrimitive< 1 >
+struct ROCKETCORE_API RotateZ : public ResolvedPrimitive< 1 >
 {
 	RotateZ(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
 	RotateZ(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
-	String ToString() const noexcept { return "rotateZ" + ResolvedPrimitive< 1 >::ToString("deg", true); }
 };
 
-struct Rotate2D : public ResolvedPrimitive< 1 >
+struct ROCKETCORE_API Rotate2D : public ResolvedPrimitive< 1 >
 {
 	Rotate2D(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
 	Rotate2D(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
-	String ToString() const noexcept { return "rotate" + ResolvedPrimitive< 1 >::ToString("deg", true); }
 };
 
-struct Rotate3D : public ResolvedPrimitive< 4 >
+struct ROCKETCORE_API Rotate3D : public ResolvedPrimitive< 4 >
 {
 	Rotate3D(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::NUMBER, Property::NUMBER, Property::NUMBER, Property::RAD }) { }
 	Rotate3D(float x, float y, float z, float angle, Property::Unit angle_unit = Property::DEG) noexcept
 		: ResolvedPrimitive({ NumericValue{x, Property::NUMBER}, NumericValue{y, Property::NUMBER}, NumericValue{z, Property::NUMBER}, NumericValue{angle, angle_unit} },
 			{ Property::NUMBER, Property::NUMBER, Property::NUMBER, Property::RAD }) { }
-	String ToString() const noexcept { return "rotate3d" + ResolvedPrimitive< 4 >::ToString("deg", true, true); }
 };
 
-struct SkewX : public ResolvedPrimitive< 1 >
+struct ROCKETCORE_API SkewX : public ResolvedPrimitive< 1 >
 {
 	SkewX(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
 	SkewX(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
-	String ToString() const noexcept { return "skewX" + ResolvedPrimitive< 1 >::ToString("deg", true); }
 };
 
-struct SkewY : public ResolvedPrimitive< 1 >
+struct ROCKETCORE_API SkewY : public ResolvedPrimitive< 1 >
 {
 	SkewY(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
 	SkewY(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
-	String ToString() const noexcept { return "skewY" + ResolvedPrimitive< 1 >::ToString("deg", true); }
 };
 
-struct Skew2D : public ResolvedPrimitive< 2 >
+struct ROCKETCORE_API Skew2D : public ResolvedPrimitive< 2 >
 {
 	Skew2D(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD, Property::RAD }) { }
 	Skew2D(float x, float y, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({NumericValue{ x, unit }, { NumericValue{ y, unit }}}, {Property::RAD, Property::RAD}) { }
-	String ToString() const noexcept { return "skew" + ResolvedPrimitive< 2 >::ToString("deg", true); }
 };
 
-struct Perspective : public UnresolvedPrimitive< 1 >
+struct ROCKETCORE_API Perspective : public UnresolvedPrimitive< 1 >
 {
 	Perspective(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
-	String ToString() const noexcept { return "perspective" + UnresolvedPrimitive< 1 >::ToString(); }
 };
 
 struct DecomposedMatrix4
@@ -273,17 +248,49 @@ struct DecomposedMatrix4
 	Vector3f skew;
 
 	bool Decompose(const Matrix4f& m);
-	String ToString() const noexcept { return "decomposedMatrix3d"; }
 };
 
 
-using PrimitiveVariant = std::variant<
-	Matrix2D, Matrix3D,
-	TranslateX, TranslateY, TranslateZ, Translate2D, Translate3D,
-	ScaleX, ScaleY, ScaleZ, Scale2D, Scale3D,
-	RotateX, RotateY, RotateZ, Rotate2D, Rotate3D,
-	SkewX, SkewY, Skew2D,
-	Perspective, DecomposedMatrix4>;
+struct ROCKETCORE_API PrimitiveVariant {
+
+	enum Type {
+		MATRIX2D, MATRIX3D,
+		TRANSLATEX, TRANSLATEY, TRANSLATEZ, TRANSLATE2D, TRANSLATE3D,
+		SCALEX, SCALEY, SCALEZ, SCALE2D, SCALE3D,
+		ROTATEX, ROTATEY, ROTATEZ, ROTATE2D, ROTATE3D,
+		SKEWX, SKEWY, SKEW2D,
+		PERSPECTIVE, DECOMPOSEDMATRIX4
+	};
+
+	PrimitiveVariant(Type type) : type(type) {}
+
+	Type type;
+
+	union {
+		Matrix2D matrix_2d;
+		Matrix3D matrix_3d;
+		TranslateX translate_x;
+		TranslateY translate_y;
+		TranslateZ translate_z;
+		Translate2D translate_2d;
+		Translate3D translate_3d;
+		ScaleX scale_x;
+		ScaleY scale_y;
+		ScaleZ scale_z;
+		Scale2D scale_2d;
+		Scale3D scale_3d;
+		RotateX rotate_x;
+		RotateY rotate_y;
+		RotateZ rotate_z;
+		Rotate2D rotate_2d;
+		Rotate3D rotate_3d;
+		SkewX skew_x;
+		SkewY skew_y;
+		Skew2D skew_2d;
+		Perspective perspective;
+		DecomposedMatrix4 decomposed_matrix_4;
+	};
+};
 
 
 /**
@@ -296,12 +303,32 @@ using PrimitiveVariant = std::variant<
 	@see Rocket::Core::Transform
 	@see Rocket::Core::PropertyParserTransform
  */
-struct Primitive
+struct ROCKETCORE_API Primitive
 {
 	PrimitiveVariant primitive;
 
-	template<typename PrimitiveType>
-	Primitive(PrimitiveType primitive) : primitive(primitive) {}
+	Primitive(Matrix2D          p) : primitive(PrimitiveVariant::MATRIX2D) { primitive.matrix_2d = p; }
+	Primitive(Matrix3D          p) : primitive(PrimitiveVariant::MATRIX3D) { primitive.matrix_3d = p; }
+	Primitive(TranslateX        p) : primitive(PrimitiveVariant::TRANSLATEX) { primitive.translate_x = p; }
+	Primitive(TranslateY        p) : primitive(PrimitiveVariant::TRANSLATEY) { primitive.translate_y = p; }
+	Primitive(TranslateZ        p) : primitive(PrimitiveVariant::TRANSLATEZ) { primitive.translate_z = p; }
+	Primitive(Translate2D       p) : primitive(PrimitiveVariant::TRANSLATE2D) { primitive.translate_2d = p; }
+	Primitive(Translate3D       p) : primitive(PrimitiveVariant::TRANSLATE3D) { primitive.translate_3d = p; }
+	Primitive(ScaleX            p) : primitive(PrimitiveVariant::SCALEX) { primitive.scale_x = p; }
+	Primitive(ScaleY            p) : primitive(PrimitiveVariant::SCALEY) { primitive.scale_y = p; }
+	Primitive(ScaleZ            p) : primitive(PrimitiveVariant::SCALEZ) { primitive.scale_z = p; }
+	Primitive(Scale2D           p) : primitive(PrimitiveVariant::SCALE2D) { primitive.scale_2d = p; }
+	Primitive(Scale3D           p) : primitive(PrimitiveVariant::SCALE3D) { primitive.scale_3d = p; }
+	Primitive(RotateX           p) : primitive(PrimitiveVariant::ROTATEX) { primitive.rotate_x = p; }
+	Primitive(RotateY           p) : primitive(PrimitiveVariant::ROTATEY) { primitive.rotate_y = p; }
+	Primitive(RotateZ           p) : primitive(PrimitiveVariant::ROTATEZ) { primitive.rotate_z = p; }
+	Primitive(Rotate2D          p) : primitive(PrimitiveVariant::ROTATE2D) { primitive.rotate_2d = p; }
+	Primitive(Rotate3D          p) : primitive(PrimitiveVariant::ROTATE3D) { primitive.rotate_3d = p; }
+	Primitive(SkewX             p) : primitive(PrimitiveVariant::SKEWX) { primitive.skew_x = p; }
+	Primitive(SkewY             p) : primitive(PrimitiveVariant::SKEWY) { primitive.skew_y = p; }
+	Primitive(Skew2D            p) : primitive(PrimitiveVariant::SKEW2D) { primitive.skew_2d = p; }
+	Primitive(Perspective       p) : primitive(PrimitiveVariant::PERSPECTIVE) { primitive.perspective = p; }
+	Primitive(DecomposedMatrix4 p) : primitive(PrimitiveVariant::DECOMPOSEDMATRIX4) { primitive.decomposed_matrix_4 = p; }
 
 	void SetIdentity() noexcept;
 
@@ -326,33 +353,6 @@ struct Primitive
 };
 
 
-template<size_t N>
-inline String ResolvedPrimitive<N>::ToString(String unit, bool rad_to_deg, bool only_unit_on_last_value) const noexcept {
-	float multiplier = 1.0f;
-	if (rad_to_deg) multiplier = 180.f / Math::ROCKET_PI;
-	String tmp;
-	String result = "(";
-	for (size_t i = 0; i < N; i++) {
-		if (TypeConverter<float, String>::Convert(values[i] * multiplier, tmp))
-			result += tmp;
-		if (!unit.empty() && (!only_unit_on_last_value || (i == N - 1)))
-			result += unit;
-		if (i != N - 1) result += ", ";
-	}
-	result += ")";
-	return result;
-}
-
-template<size_t N>
-inline String UnresolvedPrimitive<N>::ToString() const noexcept {
-	String result = "(";
-	for (size_t i = 0; i < N; i++) {
-		result += values[i].ToString();
-		if (i != N - 1) result += ", ";
-	}
-	result += ")";
-	return result;
-}
 
 }
 }

+ 5 - 4
Include/Rocket/Core/Tween.h

@@ -29,6 +29,7 @@
 #define ROCKETCORETWEEN_H
 
 #include <array>
+#include "Math.h"
 
 namespace Rocket {
 namespace Core {
@@ -91,7 +92,7 @@ public:
 	}
 	static float circular(float t)
 	{
-		return 1.f - sqrt(1.f - t * t);
+		return 1.f - Math::SquareRoot(1.f - t * t);
 	}
 	static float cubic(float t)
 	{
@@ -101,13 +102,13 @@ public:
 	{
 		if (t == 0) return t;
 		if (t == 1) return t;
-		return -exp(7.24f*(t-1.f))*sin((t - 1.1f)*2.f*Math::ROCKET_PI / 0.4f);
+		return -Math::Exp(7.24f*(t-1.f))*Math::Sin((t - 1.1f)*2.f*Math::ROCKET_PI / 0.4f);
 	}
 	static float exponential(float t)
 	{
 		if (t == 0) return t;
 		if (t == 1) return t;
-		return exp(7.24f*(t - 1.f));
+		return Math::Exp(7.24f*(t - 1.f));
 	}
 	static float linear(float t)
 	{
@@ -127,7 +128,7 @@ public:
 	}
 	static float sine(float t)
 	{
-		return 1.f - cos(t*Math::ROCKET_PI*0.5f);
+		return 1.f - Math::Cos(t*Math::ROCKET_PI*0.5f);
 	}
 
 	bool operator==(const Tween& other) const { return type_in == other.type_in && type_out == other.type_out && callback == other.callback; }

+ 4 - 1
Include/Rocket/Core/TypeConverter.inl

@@ -353,13 +353,16 @@ public:
 	}
 };
 
+
+ROCKETCORE_API String ToString(const Transform& transform);
+
 template<>
 class TypeConverter< TransformRef, String >
 {
 public:
 	static bool Convert(const TransformRef& src, String& dest)
 	{
-		if (src) dest = src->ToString();
+		if (src) dest = ToString(*src);
 		else dest = "none";
 		return true;
 	}

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

@@ -74,7 +74,6 @@ typedef unsigned __int64 uint64_t;
 #include "Vector4.h"
 #include "Matrix4.h"
 #include "String.h"
-#include "Transform.h"
 
 namespace Rocket {
 namespace Core {
@@ -97,6 +96,7 @@ class Element;
 class ElementAnimation;
 class Property;
 class Variant;
+class Transform;
 
 // Types for external interfaces.
 typedef uintptr_t FileHandle;

+ 2 - 2
Include/Rocket/Core/Vector2.inl

@@ -77,8 +77,8 @@ template < >
 inline Vector2< float > Vector2< float >::Round() const
 {
 	Vector2 < float > result;
-	result.x = std::roundf(x);
-	result.y = std::roundf(y);
+	result.x = Math::RoundFloat(x);
+	result.y = Math::RoundFloat(y);
 	return result;
 }
 

+ 4 - 2
Include/Rocket/Core/Vector3.inl

@@ -25,6 +25,8 @@
  *
  */
 
+#include <type_traits>
+
 namespace Rocket {
 namespace Core {
 
@@ -65,12 +67,12 @@ Type Vector3< Type >::SquaredMagnitude() const
 template < typename Type >
 Vector3< Type > Vector3< Type >::Normalise() const
 {
-	ROCKET_STATIC_ASSERT(false, Invalid_Operation);
+	ROCKET_STATIC_ASSERT(std::is_floating_point< Type >::value, Invalid_Operation);
 	return *this;
 }
 
 template <>
-Vector3< float > Vector3< float >::Normalise() const
+inline Vector3< float > Vector3< float >::Normalise() const
 {
 	float magnitude = Magnitude();
 	if (Math::IsZero(magnitude))

+ 3 - 1
Include/Rocket/Core/Vector4.inl

@@ -25,6 +25,8 @@
  *
  */
 
+#include <type_traits>
+
 namespace Rocket {
 namespace Core {
 
@@ -70,7 +72,7 @@ Type Vector4< Type >::SquaredMagnitude() const
 template < typename Type >
 Vector4< Type > Vector4< Type >::Normalise() const
 {
-	ROCKET_STATIC_ASSERT(false, Invalid_Operation);
+	ROCKET_STATIC_ASSERT(std::is_floating_point< Type >::value, Invalid_Operation);
 	return *this;
 }
 

+ 22 - 0
LICENSE

@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2019 The RmlUi Team, and contributors
+Copyright (c) 2008-2014 CodePoint Ltd, Shift Technology Ltd, 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.

+ 0 - 1
Samples/basic/animation/src/main.cpp

@@ -32,7 +32,6 @@
 #include <Shell.h>
 #include <Rocket/Core/TransformPrimitive.h>
 
-#include <cmath>
 #include <sstream>
 
 

+ 1 - 1
Samples/basic/drag/data/icon.rcss

@@ -13,7 +13,7 @@ icon
     background-decorator: image;
     background-image: ../../../assets/present.tga 0px 0px 100px 100px;
     
-    font-size: 12;
+    font-size: 12px;
     text-align: center;
     text-shadow: 1px 1px black;
     

+ 1 - 1
Samples/basic/sdl2/src/SystemInterfaceSDL2.cpp

@@ -402,7 +402,7 @@ int RocketSDL2SystemInterface::GetKeyModifiers()
     return retval;
 }
 
-float RocketSDL2SystemInterface::GetElapsedTime()
+double RocketSDL2SystemInterface::GetElapsedTime()
 {
 	return SDL_GetTicks() / 1000;
 }

+ 1 - 1
Samples/basic/sdl2/src/SystemInterfaceSDL2.h

@@ -38,7 +38,7 @@ public:
     Rocket::Core::Input::KeyIdentifier TranslateKey(SDL_Keycode sdlkey);
     int TranslateMouseButton(Uint8 button);
 	int GetKeyModifiers();
-	float GetElapsedTime();
+	double GetElapsedTime();
     bool LogMessage(Rocket::Core::Log::Type type, const Rocket::Core::String& message);
 };
 #endif

+ 1 - 1
Samples/luainvaders/data/game.rml

@@ -26,7 +26,7 @@
 				padding: 9px 0px 0px 65px;
 				margin: 0px 20px;
 
-				font-size: 20;
+				font-size: 20px;
 
 				background-decorator: tiled-horizontal;
 				background-left-image: ../../assets/invader.tga 147px 55px 229px 0px;

+ 1 - 1
Samples/luainvaders/data/start_game.rml

@@ -36,7 +36,7 @@ function StartGame.SetupGame(event,document)
     --some lua trickery coming up. Compiling a string at runtime that will return the values,
     --because they are comma separated. For example, if the user chose "Denim", then the
     --compiled string would look like "return 21,96,189"
-    local red,green,blue = loadstring('return '..event.parameters['colour']) ()
+    local red,green,blue = load('return '..event.parameters['colour']) ()
 	Game.SetDefenderColour(Colourb.new(red,green,blue,255))
 	
 	local elem = Window.LoadMenu('game',document):GetElementById('game')

+ 5 - 0
Samples/shell/include/ShellOpenGL.h

@@ -45,6 +45,11 @@
 #include <GL/gl.h>
 #include <GL/glext.h>
 #include <GL/glu.h>
+// The None define from X.h conflicts with Rocket code base,
+// use the constant 0L instead where necessary
+#ifdef None
+  #undef None
+#endif
 #endif
 
 #endif

+ 3 - 3
Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp

@@ -50,10 +50,10 @@ void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 		glViewport(0, 0, width, height);
 		projection = Rocket::Core::Matrix4f::ProjectOrtho(0, width, height, 0, -1, 1);
 		glMatrixMode(GL_PROJECTION);
-		glLoadMatrixf(projection);
+		glLoadMatrixf(projection.data());
 		view = Rocket::Core::Matrix4f::Identity();
 		glMatrixMode(GL_MODELVIEW);
-		glLoadMatrixf(view);
+		glLoadMatrixf(view.data());
 
 		if(m_rocket_context != NULL)
 		{
@@ -106,7 +106,7 @@ bool ShellRenderInterfaceOpenGL::AttachToNative(void *nativeWindow)
 void ShellRenderInterfaceOpenGL::DetachFromNative()
 {
 	// Shutdown OpenGL	
-	glXMakeCurrent(this->nwData.display, None, NULL);
+	glXMakeCurrent(this->nwData.display, 0L, NULL);
 	glXDestroyContext(this->nwData.display, this->gl_context);
 	this->gl_context = NULL;
 }

+ 2 - 2
Samples/shell/src/x11/ShellX11.cpp

@@ -89,7 +89,7 @@ bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_
 							GLX_BLUE_SIZE, 8,
 							GLX_DEPTH_SIZE, 24,
 							GLX_STENCIL_SIZE, 8,
-							None};
+							0L};
 
 	visual_info = glXChooseVisual(display, screen, attribute_list);
 	if (visual_info == NULL)
@@ -158,7 +158,7 @@ bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_
 	}
 
 	// Set the window title and show the window.
-	XSetStandardProperties(display, window, name, "", None, NULL, 0, NULL);
+	XSetStandardProperties(display, window, name, "", 0L, NULL, 0, NULL);
 	XMapRaised(display, window);
 
 	shell_renderer = _shell_renderer;

+ 2 - 2
Samples/tutorial/datagrid/data/tutorial.rcss

@@ -3,7 +3,7 @@ body
 	font-family: Delicious;
 	font-weight: normal;
 	font-style: normal;
-	font-size: 15;
+	font-size: 15px;
 	color: white;
 }
 
@@ -35,7 +35,7 @@ div#title-bar span
 	padding-top: 17px;
 	padding-bottom: 48px;
 
-	font-size: 22;
+	font-size: 22px;
 	font-weight: bold;
 
 	text-shadow: 2px 2px black;

+ 2 - 2
Samples/tutorial/datagrid_tree/data/tutorial.rcss

@@ -3,7 +3,7 @@ body
 	font-family: Delicious;
 	font-weight: normal;
 	font-style: normal;
-	font-size: 15;
+	font-size: 15px;
 	color: white;
 }
 
@@ -35,7 +35,7 @@ div#title-bar span
 	padding-top: 17px;
 	padding-bottom: 48px;
 
-	font-size: 22;
+	font-size: 22px;
 	font-weight: bold;
 
 	text-shadow: 2px 2px black;

+ 1 - 1
Samples/tutorial/template/data/tutorial.rcss

@@ -3,7 +3,7 @@ body
 	font-family: Delicious;
 	font-weight: normal;
 	font-style: normal;
-	font-size: 15;
+	font-size: 15px;
 	color: white;
 }
 

+ 1 - 1
Samples/tutorial/tutorial_drag/data/tutorial.rcss

@@ -19,7 +19,7 @@ icon
     background-decorator: image;
     background-image: ../../../assets/present.tga 0px 0px 100px 100px;
     
-    font-size: 12;
+    font-size: 12px;
     text-align: center;
     text-shadow: 1px 1px black;
 }

+ 2 - 2
Source/Core/BitmapFont/FontFaceLayer.h

@@ -60,14 +60,14 @@ public:
 	/// @param[in] clone The layer to optionally clone geometry and texture data from.
 	/// @param[in] deep_clone If true, the clones geometry will be completely cloned and the effect will have no option to affect even the glyph origins.
 	/// @return True if the layer was generated successfully, false if not.
-	virtual bool Initialise(const FontFaceHandle* handle, FontEffect* effect = NULL, const Rocket::Core::FontFaceLayer* clone = NULL, bool deep_clone = false);
+	virtual bool Initialise(const Rocket::Core::FontFaceHandle* handle, FontEffect* effect = NULL, const Rocket::Core::FontFaceLayer* clone = NULL, bool deep_clone = false) override;
 
 	/// Generates the texture data for a layer (for the texture database).
 	/// @param[out] texture_data The pointer to be set to the generated texture data.
 	/// @param[out] texture_dimensions The dimensions of the texture.
 	/// @param[in] glyphs The glyphs required by the font face handle.
 	/// @param[in] texture_id The index of the texture within the layer to generate.
-	virtual bool GenerateTexture(const byte*& texture_data, Vector2i& texture_dimensions, int texture_id);
+	virtual bool GenerateTexture(const byte*& texture_data, Vector2i& texture_dimensions, int texture_id) override;
 
 };
 

+ 1 - 1
Source/Core/Clock.cpp

@@ -32,7 +32,7 @@
 namespace Rocket {
 namespace Core {
 
-double Clock::GetElapsedTime()
+ROCKETCORE_API double Clock::GetElapsedTime()
 {
 	SystemInterface* system_interface = GetSystemInterface();
 	if (system_interface != NULL)

+ 1 - 1
Source/Core/Clock.h

@@ -41,7 +41,7 @@ class Clock
 public:
 	/// Get the elapsed time since application startup
 	/// @return Seconds elapsed since application startup.
-	static double GetElapsedTime();
+	ROCKETCORE_API static double GetElapsedTime();
 };
 
 }

+ 1 - 1
Source/Core/ComputeProperty.cpp

@@ -163,7 +163,7 @@ float ComputeFontsize(const Property& property, const Style::ComputedValues& val
 		{
 		case Property::PERCENT:
 			multiplier = 0.01f;
-			[[fallthrough]];
+			//[[fallthrough]];
 		case Property::EM:
 			if (!parent_values)
 				return 0;

+ 11 - 5
Source/Core/Context.cpp

@@ -40,7 +40,7 @@ namespace Core {
 
 const float DOUBLE_CLICK_TIME = 0.5f;
 
-Context::Context(const String& name) : name(name), dimensions(0, 0), mouse_position(0, 0), clip_origin(-1, -1), clip_dimensions(-1, -1), density_independent_pixel_ratio(1.0f), view_state()
+Context::Context(const String& name) : name(name), dimensions(0, 0), density_independent_pixel_ratio(1.0f), mouse_position(0, 0), clip_origin(-1, -1), clip_dimensions(-1, -1), view_state()
 {
 	instancer = NULL;
 
@@ -65,7 +65,7 @@ Context::Context(const String& name) : name(name), dimensions(0, 0), mouse_posit
 	document_focus_history.push_back(root);
 	focus = root;
 
-	enable_cursor = false;
+	enable_cursor = true;
 
 	drag_started = false;
 	drag_verbose = false;
@@ -374,6 +374,8 @@ void Context::UnloadAllDocuments()
 // Enables or disables the mouse cursor.
 void Context::EnableMouseCursor(bool enable)
 {
+	// The cursor is set to an invalid name so that it is forced to update in the next update loop.
+	cursor_name = ":reset:";
 	enable_cursor = enable;
 }
 
@@ -941,12 +943,16 @@ void Context::UpdateHoverChain(const Dictionary& parameters, const Dictionary& d
 
 	if(enable_cursor)
 	{
-		String new_mouse_cursor;
+		String new_cursor_name;
 
 		if (hover)
-			new_mouse_cursor = hover->GetComputedValues().cursor;
+			new_cursor_name = hover->GetComputedValues().cursor;
 
-		GetSystemInterface()->SetMouseCursor(new_mouse_cursor);
+		if(new_cursor_name != cursor_name)
+		{
+			GetSystemInterface()->SetMouseCursor(new_cursor_name);
+			cursor_name = new_cursor_name;
+		}
 	}
 
 	// Build the new hover chain.

+ 16 - 11
Source/Core/Element.cpp

@@ -917,7 +917,8 @@ bool Element::HasAttribute(const String& name) const
 // Removes an attribute from the element
 void Element::RemoveAttribute(const String& name)
 {
-	if (auto it = attributes.find(name); it != attributes.end())
+	auto it = attributes.find(name);
+	if (it != attributes.end())
 	{
 		attributes.erase(it);
 
@@ -959,13 +960,13 @@ Context* Element::GetContext()
 void Element::SetAttributes(const ElementAttributes* _attributes)
 {
 	attributes.reserve(attributes.size() + _attributes->size());
-	for (auto& [key, value] : *_attributes)
-		attributes[key] = value;
+	for (auto& pair : *_attributes)
+		attributes[pair.first] = pair.second;
 
 	AttributeNameList changed_attributes;
 	changed_attributes.reserve(_attributes->size());
-	for (auto& [key, value] : *_attributes)
-		changed_attributes.insert(key);
+	for (auto& pair : *_attributes)
+		changed_attributes.insert(pair.first);
 	OnAttributeChange(changed_attributes);
 }
 
@@ -2039,8 +2040,10 @@ void Element::GetRML(String& content)
 	content += "<";
 	content += tag;
 
-	for( auto& [name, variant] : attributes)
+	for( auto& pair : attributes)
 	{
+		auto& name = pair.first;
+		auto& variant = pair.second;
 		String value;
 		if (variant.GetInto(value))
 			content += " " + name + "=\"" + value + "\"";
@@ -2286,7 +2289,8 @@ bool Element::Animate(const String & property_name, const Property & target_valu
 {
 	bool result = false;
 
-	if (auto it_animation = StartAnimation(property_name, start_value, num_iterations, alternate_direction, delay); it_animation != animations.end())
+	auto it_animation = StartAnimation(property_name, start_value, num_iterations, alternate_direction, delay);
+	if (it_animation != animations.end())
 	{
 		result = it_animation->AddKey(duration, target_value, *this, tween, true);
 		if (!result)
@@ -2489,7 +2493,8 @@ void Element::AdvanceAnimations()
 
 		for (auto it = it_completed; it != animations.end(); ++it)
 		{
-			dictionary_list.emplace_back().emplace("property", it->GetPropertyName());
+			dictionary_list.emplace_back();
+			dictionary_list.back().emplace("property", it->GetPropertyName());
 			is_transition.push_back(it->IsTransition());
 		}
 
@@ -2580,7 +2585,7 @@ void Element::UpdateTransformState()
 			if (have_perspective && context)
 			{
 				if (!transform_state)
-					transform_state = std::make_unique<TransformState>();
+					transform_state.reset(new TransformState);
 				perspective_value.view_size = context->GetDimensions();
 				transform_state->SetPerspective(&perspective_value);
 			}
@@ -2638,7 +2643,7 @@ void Element::UpdateTransformState()
 			if (have_local_perspective && context)
 			{
 				if (!transform_state)
-					transform_state = std::make_unique<TransformState>();
+					transform_state.reset(new TransformState);
 				local_perspective.view_size = context->GetDimensions();
 				transform_state->SetLocalPerspective(&local_perspective);
 			}
@@ -2661,7 +2666,7 @@ void Element::UpdateTransformState()
 					* Matrix4f::Translate(-transform_origin);
 
 				if (!transform_state)
-					transform_state = std::make_unique<TransformState>();
+					transform_state.reset(new TransformState);
 				transform_state->SetTransform(&transform_value);
 			}
 			else if (transform_state)

+ 13 - 32
Source/Core/ElementAnimation.cpp

@@ -130,7 +130,7 @@ static Property InterpolateProperties(const Property & p0, const Property& p1, f
 		}
 
 		// Build the new, interpolating transform
-		auto t = std::make_unique<Transform>();
+		std::unique_ptr<Transform> t(new Transform);
 		t->GetPrimitives().reserve(t0->GetPrimitives().size());
 
 		for (size_t i = 0; i < prim0.size(); i++)
@@ -172,8 +172,8 @@ static PrepareTransformResult PrepareTransformPair(Transform& t0, Transform& t1,
 		bool same_primitives = true;
 		for (size_t i = 0; i < prims0.size(); i++)
 		{
-			auto p0_type = prims0[i].primitive.index();
-			auto p1_type = prims1[i].primitive.index();
+			auto p0_type = prims0[i].primitive.type;
+			auto p1_type = prims1[i].primitive.type;
 			if (p0_type != p1_type)
 			{
 				// They are not the same, but see if we can convert them to their more generic form
@@ -182,9 +182,9 @@ static PrepareTransformResult PrepareTransformPair(Transform& t0, Transform& t1,
 					same_primitives = false;
 					break;
 				}
-				if (prims0[i].primitive.index() != p0_type)
+				if (prims0[i].primitive.type != p0_type)
 					(int&)result |= (int)PrepareTransformResult::ChangedT0;
-				if (prims1[i].primitive.index() != p1_type)
+				if (prims1[i].primitive.type != p1_type)
 					(int&)result |= (int)PrepareTransformResult::ChangedT1;
 			}
 		}
@@ -218,11 +218,11 @@ static PrepareTransformResult PrepareTransformPair(Transform& t0, Transform& t1,
 		for (size_t i_small = 0; i_small < small.size(); i_small++)
 		{
 			match_success = false;
-			auto small_type = small[i_small].primitive.index();
+			auto small_type = small[i_small].primitive.type;
 
 			for (; i_big < big.size(); i_big++)
 			{
-				auto big_type = big[i_big].primitive.index();
+				auto big_type = big[i_big].primitive.type;
 
 				if (small_type == big_type)
 				{
@@ -233,7 +233,7 @@ static PrepareTransformResult PrepareTransformPair(Transform& t0, Transform& t1,
 				{
 					// They matched in their more generic form, one or both primitives converted
 					match_success = true;
-					if (big[i_big].primitive.index() != big_type)
+					if (big[i_big].primitive.type != big_type)
 						changed_big = true;
 				}
 
@@ -283,29 +283,10 @@ static PrepareTransformResult PrepareTransformPair(Transform& t0, Transform& t1,
 	// If we get here, things get tricky. Need to do full matrix interpolation.
 	// In short, we decompose the Transforms into translation, rotation, scale, skew and perspective components. 
 	// Then, during update, interpolate these components and combine into a new transform matrix.
-	if constexpr(true)
-	{
-		if (!CombineAndDecompose(t0, element))
-			return PrepareTransformResult::Invalid;
-		if (!CombineAndDecompose(t1, element))
-			return PrepareTransformResult::Invalid;
-	}
-	else
-	{
-		// Bad "flat" matrix interpolation
-		for (Transform* t : { &t0, &t1 })
-		{
-			Matrix4f transform_value = Matrix4f::Identity();
-			for (const auto& primitive : t->GetPrimitives())
-			{
-				Matrix4f m;
-				if (primitive.ResolveTransform(m, element))
-					transform_value *= m;
-			}
-			t->ClearPrimitives();
-			t->AddPrimitive({ Matrix3D{transform_value} });
-		}
-	}
+	if (!CombineAndDecompose(t0, element))
+		return PrepareTransformResult::Invalid;
+	if (!CombineAndDecompose(t1, element))
+		return PrepareTransformResult::Invalid;
 
 	return PrepareTransformResult::ChangedT0andT1;
 }
@@ -541,4 +522,4 @@ Property ElementAnimation::UpdateAndGetProperty(double world_time, Element& elem
 
 
 }
-}
+}

+ 2 - 1
Source/Core/ElementStyle.cpp

@@ -167,7 +167,8 @@ void ElementStyle::TransitionPropertyChanges(Element* element, PropertyNameList&
 			{
 				for (auto& transition : transition_list.transitions)
 				{
-					if (auto it = properties.find(transition.name); it != properties.end())
+					auto it = properties.find(transition.name);
+					if (it != properties.end())
 					{
 						if (add_transition(transition))
 							properties.erase(it);

+ 1 - 1
Source/Core/ElementTextDefault.cpp

@@ -222,7 +222,7 @@ bool ElementTextDefault::GenerateLine(WString& line, int& line_length, float& li
 		{
 			if (!line.empty() &&
 				(line_width + token_width > maximum_line_width ||
-				 LastToken(next_token_begin, string_end, collapse_white_space, break_at_endline) && line_width + token_width > maximum_line_width - right_spacing_width))
+				 (LastToken(next_token_begin, string_end, collapse_white_space, break_at_endline) && line_width + token_width > maximum_line_width - right_spacing_width)))
 			{
 				return false;
 			}

+ 4 - 4
Source/Core/ElementUtilities.cpp

@@ -147,13 +147,13 @@ int ElementUtilities::GetStringWidth(Element* element, const WString& string)
 void ElementUtilities::BindEventAttributes(Element* element)
 {
 	// Check for and instance the on* events
-	for (const auto& [name, variant] : element->GetAttributes())
+	for (const auto& pair: element->GetAttributes())
 	{
-		if (name.substr(0, 2) == "on")
+		if (pair.first.substr(0, 2) == "on")
 		{
-			EventListener* listener = Factory::InstanceEventListener(variant.Get<String>(), element);
+			EventListener* listener = Factory::InstanceEventListener(pair.second.Get<String>(), element);
 			if (listener)
-				element->AddEventListener(name.substr(2), listener, false);
+				element->AddEventListener(pair.first.substr(2), listener, false);
 		}
 	}
 }

+ 1 - 1
Source/Core/FontFaceLayer.h

@@ -52,7 +52,7 @@ class FontFaceLayer
 {
 public:
 	FontFaceLayer();
-	~FontFaceLayer();
+	virtual ~FontFaceLayer();
 
 	/// Generates the character and texture data for the layer.
 	/// @param[in] handle The handle generating this layer.

+ 1 - 0
Source/Core/FreeType/FontProvider.cpp

@@ -87,6 +87,7 @@ void FontProvider::Shutdown()
 			ft_library = NULL;
 		}
 
+		FontDatabase::RemoveFontProvider(instance);
 		delete instance;
 		instance = NULL;
 	}

+ 0 - 40
Source/Core/Lua/Context.cpp

@@ -77,13 +77,6 @@ int ContextAddEventListener(lua_State* L, Context* obj)
     return 0;
 }
 
-int ContextAddMouseCursor(lua_State* L, Context* obj)
-{
-    Document* cursor_doc = LuaType<Document>::check(L,1);
-    obj->AddMouseCursor(cursor_doc);
-    return 0;   
-}
-
 int ContextCreateDocument(lua_State* L, Context* obj)
 {
     const char* tag;
@@ -105,39 +98,18 @@ int ContextLoadDocument(lua_State* L, Context* obj)
     return 1;
 }
 
-int ContextLoadMouseCursor(lua_State* L, Context* obj)
-{
-    const char* path = luaL_checkstring(L,1);
-    Document* doc = obj->LoadMouseCursor(path);
-    LuaType<Document>::push(L,doc);
-    return 1;
-}
-
 int ContextRender(lua_State* L, Context* obj)
 {
     lua_pushboolean(L,obj->Render());
     return 1;
 }
 
-int ContextShowMouseCursor(lua_State* L, Context* obj)
-{
-    bool show = CHECK_BOOL(L,1);
-    obj->ShowMouseCursor(show);
-    return 0;
-}
-
 int ContextUnloadAllDocuments(lua_State* L, Context* obj)
 {
     obj->UnloadAllDocuments();
     return 0;
 }
 
-int ContextUnloadAllMouseCursors(lua_State* L, Context* obj)
-{
-    obj->UnloadAllMouseCursors();
-    return 0;
-}
-
 int ContextUnloadDocument(lua_State* L, Context* obj)
 {
     Document* doc = LuaType<Document>::check(L,1);
@@ -145,13 +117,6 @@ int ContextUnloadDocument(lua_State* L, Context* obj)
     return 0;
 }
 
-int ContextUnloadMouseCursor(lua_State* L, Context* obj)
-{
-    const char* name = luaL_checkstring(L,1);
-    obj->UnloadMouseCursor(name);
-    return 0;
-}
-
 int ContextUpdate(lua_State* L, Context* obj)
 {
     lua_pushboolean(L,obj->Update());
@@ -229,16 +194,11 @@ int ContextSetAttrdimensions(lua_State* L)
 RegType<Context> ContextMethods[] =
 {
     LUAMETHOD(Context,AddEventListener)
-    LUAMETHOD(Context,AddMouseCursor)
     LUAMETHOD(Context,CreateDocument)
     LUAMETHOD(Context,LoadDocument)
-    LUAMETHOD(Context,LoadMouseCursor)
     LUAMETHOD(Context,Render)
-    LUAMETHOD(Context,ShowMouseCursor)
     LUAMETHOD(Context,UnloadAllDocuments)
-    LUAMETHOD(Context,UnloadAllMouseCursors)
     LUAMETHOD(Context,UnloadDocument)
-    LUAMETHOD(Context,UnloadMouseCursor)
     LUAMETHOD(Context,Update)
     { NULL, NULL },
 };

+ 0 - 5
Source/Core/Lua/Context.h

@@ -40,16 +40,11 @@ template<> void ExtraInit<Context>(lua_State* L, int metatable_index);
 
 //methods
 int ContextAddEventListener(lua_State* L, Context* obj);
-int ContextAddMouseCursor(lua_State* L, Context* obj);
 int ContextCreateDocument(lua_State* L, Context* obj);
 int ContextLoadDocument(lua_State* L, Context* obj);
-int ContextLoadMouseCursor(lua_State* L, Context* obj);
 int ContextRender(lua_State* L, Context* obj);
-int ContextShowMouseCursor(lua_State* L, Context* obj);
 int ContextUnloadAllDocuments(lua_State* L, Context* obj);
-int ContextUnloadAllMouseCursors(lua_State* L, Context* obj);
 int ContextUnloadDocument(lua_State* L, Context* obj);
-int ContextUnloadMouseCursor(lua_State* L, Context* obj);
 int ContextUpdate(lua_State* L, Context* obj);
 
 //getters

+ 6 - 0
Source/Core/Math.cpp

@@ -93,6 +93,12 @@ ROCKETCORE_API float ATan2(float y, float x)
 	return atan2f(y, x);
 }
 
+// Evaluates the natural exponential function on a value.
+ROCKETCORE_API float Exp(float value)
+{
+	return exp(value);
+}
+
 // Converts an angle from radians to degrees.
 ROCKETCORE_API float RadiansToDegrees(float angle)
 {

+ 4 - 2
Source/Core/PropertyParserAnimation.cpp

@@ -132,7 +132,8 @@ static bool ParseAnimation(Property & property, const StringList& animation_valu
 				continue;
 
 			// See if we have a <keyword> or <tween> specifier as defined in keywords
-			if (auto it = keywords.find(argument); it != keywords.end() && it->second.ValidAnimation())
+			auto it = keywords.find(argument); 
+			if (it != keywords.end() && it->second.ValidAnimation())
 			{
 				switch (it->second.type)
 				{
@@ -247,7 +248,8 @@ static bool ParseTransition(Property & property, const StringList& transition_va
 				continue;
 
 			// See if we have a <keyword> or <tween> specifier as defined in keywords
-			if (auto it = keywords.find(argument); it != keywords.end() && it->second.ValidTransition())
+			auto it = keywords.find(argument);
+			if (it != keywords.end() && it->second.ValidTransition())
 			{
 				if (it->second.type == Keyword::NONE)
 				{

+ 1 - 1
Source/Core/PropertyParserTransform.cpp

@@ -53,7 +53,7 @@ bool PropertyParserTransform::ParseValue(Property& property, const String& value
 		return true;
 	}
 
-	auto transform = std::make_unique<Transform>();
+	std::unique_ptr<Transform> transform(new Transform);
 
 	char const* next = value.c_str();
 

+ 1 - 0
Source/Core/String.cpp

@@ -27,6 +27,7 @@
 
 #include "precompiled.h"
 #include "../../Include/Rocket/Core/String.h"
+#include <stdarg.h>
 
 namespace Rocket {
 namespace Core {

+ 2 - 1
Source/Core/StyleSheetNode.cpp

@@ -241,7 +241,8 @@ bool StyleSheetNode::GetVolatilePseudoClasses(PseudoClassList& volatile_pseudo_c
 
 		if (self_volatile)
 		{
-			if (auto it = std::find(volatile_pseudo_classes.begin(), volatile_pseudo_classes.end(), name); it == volatile_pseudo_classes.end())
+			auto it = std::find(volatile_pseudo_classes.begin(), volatile_pseudo_classes.end(), name);
+			if (it == volatile_pseudo_classes.end())
 				volatile_pseudo_classes.push_back(name);
 		}
 

+ 1 - 1
Source/Core/StyleSheetSpecification.cpp

@@ -264,7 +264,7 @@ void StyleSheetSpecification::RegisterDefaultProperties()
 	RegisterProperty(TEXT_TRANSFORM, "none", true, true).AddParser("keyword", "none, capitalize, uppercase, lowercase");
 	RegisterProperty(WHITE_SPACE, "normal", true, true).AddParser("keyword", "normal, pre, nowrap, pre-wrap, pre-line");
 
-	RegisterProperty(CURSOR, "auto", true, false).AddParser("keyword", "auto").AddParser("string");
+	RegisterProperty(CURSOR, "", true, false).AddParser("string");
 
 	// Functional property specifications.
 	RegisterProperty(DRAG, "none", false, false).AddParser("keyword", "none, drag, drag-drop, block, clone");

+ 2 - 1
Source/Core/Transform.cpp

@@ -72,9 +72,10 @@ const Transforms::Primitive & Transform::GetPrimitive(int i) const noexcept
 	return primitives[i];
 }
 
-String Transform::ToString() const
+ROCKETCORE_API String ToString(const Transform& transform)
 {
 	String result;
+	auto& primitives = transform.GetPrimitives();
 	for (size_t i = 0; i < primitives.size(); i++)
 	{
 		result += primitives[i].ToString();

+ 279 - 29
Source/Core/TransformPrimitive.cpp

@@ -27,6 +27,7 @@
 
 #include "precompiled.h"
 #include "../../Include/Rocket/Core/TransformPrimitive.h"
+#include "../../Include/Rocket/Core/TypeConverter.h"
 #include <iostream>
 #include <unordered_map>
 
@@ -303,6 +304,39 @@ struct ResolveTransformVisitor
 		return false;
 	}
 
+
+	bool run(const PrimitiveVariant& primitive)
+	{
+		switch (primitive.type)
+		{
+		case PrimitiveVariant::MATRIX2D: return this->operator()(primitive.matrix_2d);
+		case PrimitiveVariant::MATRIX3D: return this->operator()(primitive.matrix_3d);
+		case PrimitiveVariant::TRANSLATEX: return this->operator()(primitive.translate_x);
+		case PrimitiveVariant::TRANSLATEY: return this->operator()(primitive.translate_y);
+		case PrimitiveVariant::TRANSLATEZ: return this->operator()(primitive.translate_z);
+		case PrimitiveVariant::TRANSLATE2D: return this->operator()(primitive.translate_2d);
+		case PrimitiveVariant::TRANSLATE3D: return this->operator()(primitive.translate_3d);
+		case PrimitiveVariant::SCALEX: return this->operator()(primitive.scale_x);
+		case PrimitiveVariant::SCALEY: return this->operator()(primitive.scale_y);
+		case PrimitiveVariant::SCALEZ: return this->operator()(primitive.scale_z);
+		case PrimitiveVariant::SCALE2D: return this->operator()(primitive.scale_2d);
+		case PrimitiveVariant::SCALE3D: return this->operator()(primitive.scale_3d);
+		case PrimitiveVariant::ROTATEX: return this->operator()(primitive.rotate_x);
+		case PrimitiveVariant::ROTATEY: return this->operator()(primitive.rotate_y);
+		case PrimitiveVariant::ROTATEZ: return this->operator()(primitive.rotate_z);
+		case PrimitiveVariant::ROTATE2D: return this->operator()(primitive.rotate_2d);
+		case PrimitiveVariant::ROTATE3D: return this->operator()(primitive.rotate_3d);
+		case PrimitiveVariant::SKEWX: return this->operator()(primitive.skew_x);
+		case PrimitiveVariant::SKEWY: return this->operator()(primitive.skew_y);
+		case PrimitiveVariant::SKEW2D: return this->operator()(primitive.skew_2d);
+		case PrimitiveVariant::PERSPECTIVE: return this->operator()(primitive.perspective);
+		case PrimitiveVariant::DECOMPOSEDMATRIX4: return this->operator()(primitive.decomposed_matrix_4);
+		default:
+			break;
+		}
+		ROCKET_ASSERT(false);
+		return false;
+	}
 };
 
 
@@ -313,7 +347,7 @@ bool Primitive::ResolveTransform(Matrix4f & m, Element & e) const noexcept
 {
 	ResolveTransformVisitor visitor{ m, e };
 
-	bool result = std::visit(visitor, primitive);
+	bool result = visitor.run(primitive);
 
 	return result;
 }
@@ -322,9 +356,10 @@ bool Primitive::ResolvePerspective(float & p, Element & e) const noexcept
 {
 	bool result = false;
 
-	if (const Perspective* perspective = std::get_if<Perspective>(&primitive))
+	if (primitive.type == PrimitiveVariant::PERSPECTIVE)
 	{
-		p = perspective->values[0].ResolveDepth(e);
+
+		p = primitive.perspective.values[0].ResolveDepth(e);
 		result = true;
 	}
 
@@ -384,12 +419,44 @@ struct SetIdentityVisitor
 		p.scale = Vector3f(1, 1, 1);
 		p.skew = Vector3f(0, 0, 0);
 	}
-};
 
 
+	void run(PrimitiveVariant& primitive)
+	{
+		switch (primitive.type)
+		{
+		case PrimitiveVariant::MATRIX2D: this->operator()(primitive.matrix_2d); break;
+		case PrimitiveVariant::MATRIX3D: this->operator()(primitive.matrix_3d); break;
+		case PrimitiveVariant::TRANSLATEX: this->operator()(primitive.translate_x); break;
+		case PrimitiveVariant::TRANSLATEY: this->operator()(primitive.translate_y); break;
+		case PrimitiveVariant::TRANSLATEZ: this->operator()(primitive.translate_z); break;
+		case PrimitiveVariant::TRANSLATE2D: this->operator()(primitive.translate_2d); break;
+		case PrimitiveVariant::TRANSLATE3D: this->operator()(primitive.translate_3d); break;
+		case PrimitiveVariant::SCALEX: this->operator()(primitive.scale_x); break;
+		case PrimitiveVariant::SCALEY: this->operator()(primitive.scale_y); break;
+		case PrimitiveVariant::SCALEZ: this->operator()(primitive.scale_z); break;
+		case PrimitiveVariant::SCALE2D: this->operator()(primitive.scale_2d); break;
+		case PrimitiveVariant::SCALE3D: this->operator()(primitive.scale_3d); break;
+		case PrimitiveVariant::ROTATEX: this->operator()(primitive.rotate_x); break;
+		case PrimitiveVariant::ROTATEY: this->operator()(primitive.rotate_y); break;
+		case PrimitiveVariant::ROTATEZ: this->operator()(primitive.rotate_z); break;
+		case PrimitiveVariant::ROTATE2D: this->operator()(primitive.rotate_2d); break;
+		case PrimitiveVariant::ROTATE3D: this->operator()(primitive.rotate_3d); break;
+		case PrimitiveVariant::SKEWX: this->operator()(primitive.skew_x); break;
+		case PrimitiveVariant::SKEWY: this->operator()(primitive.skew_y); break;
+		case PrimitiveVariant::SKEW2D: this->operator()(primitive.skew_2d); break;
+		case PrimitiveVariant::PERSPECTIVE: this->operator()(primitive.perspective); break;
+		case PrimitiveVariant::DECOMPOSEDMATRIX4: this->operator()(primitive.decomposed_matrix_4); break;
+		default:
+			ROCKET_ASSERT(false);
+			break;
+		}
+	}
+};
+
 void Primitive::SetIdentity() noexcept
 {
-	std::visit(SetIdentityVisitor{}, primitive);
+	SetIdentityVisitor{}.run(primitive);
 }
 
 
@@ -457,12 +524,45 @@ struct PrepareVisitor
 		// Perspective must be decomposed
 		return false;
 	}
+
+	bool run(PrimitiveVariant& primitive)
+	{
+		switch (primitive.type)
+		{
+		case PrimitiveVariant::MATRIX2D: return this->operator()(primitive.matrix_2d);
+		case PrimitiveVariant::MATRIX3D: return this->operator()(primitive.matrix_3d);
+		case PrimitiveVariant::TRANSLATEX: return this->operator()(primitive.translate_x);
+		case PrimitiveVariant::TRANSLATEY: return this->operator()(primitive.translate_y);
+		case PrimitiveVariant::TRANSLATEZ: return this->operator()(primitive.translate_z);
+		case PrimitiveVariant::TRANSLATE2D: return this->operator()(primitive.translate_2d);
+		case PrimitiveVariant::TRANSLATE3D: return this->operator()(primitive.translate_3d);
+		case PrimitiveVariant::SCALEX: return this->operator()(primitive.scale_x);
+		case PrimitiveVariant::SCALEY: return this->operator()(primitive.scale_y);
+		case PrimitiveVariant::SCALEZ: return this->operator()(primitive.scale_z);
+		case PrimitiveVariant::SCALE2D: return this->operator()(primitive.scale_2d);
+		case PrimitiveVariant::SCALE3D: return this->operator()(primitive.scale_3d);
+		case PrimitiveVariant::ROTATEX: return this->operator()(primitive.rotate_x);
+		case PrimitiveVariant::ROTATEY: return this->operator()(primitive.rotate_y);
+		case PrimitiveVariant::ROTATEZ: return this->operator()(primitive.rotate_z);
+		case PrimitiveVariant::ROTATE2D: return this->operator()(primitive.rotate_2d);
+		case PrimitiveVariant::ROTATE3D: return this->operator()(primitive.rotate_3d);
+		case PrimitiveVariant::SKEWX: return this->operator()(primitive.skew_x);
+		case PrimitiveVariant::SKEWY: return this->operator()(primitive.skew_y);
+		case PrimitiveVariant::SKEW2D: return this->operator()(primitive.skew_2d);
+		case PrimitiveVariant::PERSPECTIVE: return this->operator()(primitive.perspective);
+		case PrimitiveVariant::DECOMPOSEDMATRIX4: return this->operator()(primitive.decomposed_matrix_4);
+		default:
+			break;
+		}
+		ROCKET_ASSERT(false);
+		return false;
+	}
 };
 
 
 bool Primitive::PrepareForInterpolation(Element & e) noexcept
 {
-	return std::visit(PrepareVisitor{ e }, primitive);
+	return PrepareVisitor{ e }.run(primitive);
 }
 
 
@@ -484,38 +584,79 @@ struct GetGenericTypeVisitor
 
 	template <typename T>
 	GenericType operator()(const T& p) { return GenericType::None; }
+
+	GenericType run(const PrimitiveVariant& primitive)
+	{
+		PrimitiveVariant result = primitive;
+		switch (primitive.type)
+		{
+		case PrimitiveVariant::TRANSLATEX:  return this->operator()(primitive.translate_x); break;
+		case PrimitiveVariant::TRANSLATEY:  return this->operator()(primitive.translate_y); break;
+		case PrimitiveVariant::TRANSLATEZ:  return this->operator()(primitive.translate_z); break;
+		case PrimitiveVariant::TRANSLATE2D: return this->operator()(primitive.translate_2d); break;
+		case PrimitiveVariant::SCALEX:      return this->operator()(primitive.scale_x); break;
+		case PrimitiveVariant::SCALEY:      return this->operator()(primitive.scale_y); break;
+		case PrimitiveVariant::SCALEZ:      return this->operator()(primitive.scale_z); break;
+		case PrimitiveVariant::SCALE2D:     return this->operator()(primitive.scale_2d); break;
+		default:
+			break;
+		}
+		return GenericType::None;
+	}
 };
 
 
 struct ConvertToGenericTypeVisitor
 {
-	PrimitiveVariant operator()(const TranslateX& p) { return Translate3D{ p.values[0], {0.0f, Property::PX}, {0.0f, Property::PX} }; }
-	PrimitiveVariant operator()(const TranslateY& p) { return Translate3D{ {0.0f, Property::PX}, p.values[0], {0.0f, Property::PX} }; }
-	PrimitiveVariant operator()(const TranslateZ& p) { return Translate3D{ {0.0f, Property::PX}, {0.0f, Property::PX}, p.values[0] }; }
-	PrimitiveVariant operator()(const Translate2D& p) { return Translate3D{ p.values[0], p.values[1], {0.0f, Property::PX} }; }
-	PrimitiveVariant operator()(const ScaleX& p) { return Scale3D{ p.values[0], 1.0f, 1.0f }; }
-	PrimitiveVariant operator()(const ScaleY& p) { return Scale3D{  1.0f, p.values[0], 1.0f }; }
-	PrimitiveVariant operator()(const ScaleZ& p) { return Scale3D{  1.0f, 1.0f, p.values[0] }; }
-	PrimitiveVariant operator()(const Scale2D& p) { return Scale3D{ p.values[0], p.values[1], 1.0f }; }
+	Translate3D operator()(const TranslateX& p) { return Translate3D{ p.values[0], {0.0f, Property::PX}, {0.0f, Property::PX} }; }
+	Translate3D operator()(const TranslateY& p) { return Translate3D{ {0.0f, Property::PX}, p.values[0], {0.0f, Property::PX} }; }
+	Translate3D operator()(const TranslateZ& p) { return Translate3D{ {0.0f, Property::PX}, {0.0f, Property::PX}, p.values[0] }; }
+	Translate3D operator()(const Translate2D& p) { return Translate3D{ p.values[0], p.values[1], {0.0f, Property::PX} }; }
+	Scale3D operator()(const ScaleX& p) { return Scale3D{ p.values[0], 1.0f, 1.0f }; }
+	Scale3D operator()(const ScaleY& p) { return Scale3D{  1.0f, p.values[0], 1.0f }; }
+	Scale3D operator()(const ScaleZ& p) { return Scale3D{  1.0f, 1.0f, p.values[0] }; }
+	Scale3D operator()(const Scale2D& p) { return Scale3D{ p.values[0], p.values[1], 1.0f }; }
 
 	template <typename T>
 	PrimitiveVariant operator()(const T& p) { ROCKET_ERROR; return p; }
+
+
+
+	PrimitiveVariant run(const PrimitiveVariant& primitive)
+	{
+		PrimitiveVariant result = primitive;
+		switch (primitive.type)
+		{
+		case PrimitiveVariant::TRANSLATEX: result.translate_3d = this->operator()(primitive.translate_x); break;
+		case PrimitiveVariant::TRANSLATEY: result.translate_3d = this->operator()(primitive.translate_y); break;
+		case PrimitiveVariant::TRANSLATEZ: result.translate_3d = this->operator()(primitive.translate_z); break;
+		case PrimitiveVariant::TRANSLATE2D: result.translate_3d = this->operator()(primitive.translate_2d); break;
+		case PrimitiveVariant::SCALEX: result.scale_3d = this->operator()(primitive.scale_x); break;
+		case PrimitiveVariant::SCALEY: result.scale_3d = this->operator()(primitive.scale_y); break;
+		case PrimitiveVariant::SCALEZ: result.scale_3d = this->operator()(primitive.scale_z); break;
+		case PrimitiveVariant::SCALE2D: result.scale_3d = this->operator()(primitive.scale_2d); break;
+		default:
+			ROCKET_ASSERT(false);
+			break;
+		}
+		return result;
+	}
 };
 
 
 
 bool Primitive::TryConvertToMatchingGenericType(Primitive & p0, Primitive & p1) noexcept
 {
-	if (p0.primitive.index() == p1.primitive.index())
+	if (p0.primitive.type == p1.primitive.type)
 		return true;
 
-	GenericType c0 = std::visit(GetGenericTypeVisitor{}, p0.primitive);
-	GenericType c1 = std::visit(GetGenericTypeVisitor{}, p1.primitive);
+	GenericType c0 = GetGenericTypeVisitor{}.run(p0.primitive);
+	GenericType c1 = GetGenericTypeVisitor{}.run(p1.primitive);
 
 	if (c0 == c1 && c0 != GenericType::None)
 	{
-		p0.primitive = std::visit(ConvertToGenericTypeVisitor{}, p0.primitive);
-		p1.primitive = std::visit(ConvertToGenericTypeVisitor{}, p1.primitive);
+		p0.primitive = ConvertToGenericTypeVisitor{}.run(p0.primitive);
+		p1.primitive = ConvertToGenericTypeVisitor{}.run(p1.primitive);
 		return true;
 	}
 
@@ -565,21 +706,48 @@ struct InterpolateVisitor
 		return true;
 	}
 
-	template <typename T>
-	bool operator()(T& p0)
+	bool run(PrimitiveVariant& variant)
 	{
-		auto& p1 = std::get<T>(other_variant);
-		return Interpolate(p0, p1);
+		ROCKET_ASSERT(variant.type == other_variant.type);
+		switch (variant.type)
+		{
+		case PrimitiveVariant::MATRIX2D: return Interpolate(variant.matrix_2d, other_variant.matrix_2d);
+		case PrimitiveVariant::MATRIX3D: return Interpolate(variant.matrix_3d, other_variant.matrix_3d);
+		case PrimitiveVariant::TRANSLATEX: return Interpolate(variant.translate_x, other_variant.translate_x);
+		case PrimitiveVariant::TRANSLATEY: return Interpolate(variant.translate_y, other_variant.translate_y);
+		case PrimitiveVariant::TRANSLATEZ: return Interpolate(variant.translate_z, other_variant.translate_z);
+		case PrimitiveVariant::TRANSLATE2D: return Interpolate(variant.translate_2d, other_variant.translate_2d);
+		case PrimitiveVariant::TRANSLATE3D: return Interpolate(variant.translate_3d, other_variant.translate_3d);
+		case PrimitiveVariant::SCALEX: return Interpolate(variant.scale_x, other_variant.scale_x);
+		case PrimitiveVariant::SCALEY: return Interpolate(variant.scale_y, other_variant.scale_y);
+		case PrimitiveVariant::SCALEZ: return Interpolate(variant.scale_z, other_variant.scale_z);
+		case PrimitiveVariant::SCALE2D: return Interpolate(variant.scale_2d, other_variant.scale_2d);
+		case PrimitiveVariant::SCALE3D: return Interpolate(variant.scale_3d, other_variant.scale_3d);
+		case PrimitiveVariant::ROTATEX: return Interpolate(variant.rotate_x, other_variant.rotate_x);
+		case PrimitiveVariant::ROTATEY: return Interpolate(variant.rotate_y, other_variant.rotate_y);
+		case PrimitiveVariant::ROTATEZ: return Interpolate(variant.rotate_z, other_variant.rotate_z);
+		case PrimitiveVariant::ROTATE2D: return Interpolate(variant.rotate_2d, other_variant.rotate_2d);
+		case PrimitiveVariant::ROTATE3D: return Interpolate(variant.rotate_3d, other_variant.rotate_3d);
+		case PrimitiveVariant::SKEWX: return Interpolate(variant.skew_x, other_variant.skew_x);
+		case PrimitiveVariant::SKEWY: return Interpolate(variant.skew_y, other_variant.skew_y);
+		case PrimitiveVariant::SKEW2D: return Interpolate(variant.skew_2d, other_variant.skew_2d);
+		case PrimitiveVariant::PERSPECTIVE: return Interpolate(variant.perspective, other_variant.perspective);
+		case PrimitiveVariant::DECOMPOSEDMATRIX4: return Interpolate(variant.decomposed_matrix_4, other_variant.decomposed_matrix_4);
+		default:
+			break;
+		}
+		ROCKET_ASSERT(false);
+		return false;
 	}
 };
 
 
 bool Primitive::InterpolateWith(const Primitive & other, float alpha) noexcept
 {
-	if (primitive.index() != other.primitive.index())
+	if (primitive.type != other.primitive.type)
 		return false;
 
-	bool result = std::visit(InterpolateVisitor{ other.primitive, alpha }, primitive);
+	bool result = InterpolateVisitor{ other.primitive, alpha }.run(primitive);
 
 	return result;
 }
@@ -587,18 +755,100 @@ bool Primitive::InterpolateWith(const Primitive & other, float alpha) noexcept
 
 
 
+
+template<size_t N>
+inline String ToString(const Transforms::ResolvedPrimitive<N>& p, String unit, bool rad_to_deg = false, bool only_unit_on_last_value = false) noexcept {
+	float multiplier = 1.0f;
+	if (rad_to_deg) multiplier = 180.f / Math::ROCKET_PI;
+	String tmp;
+	String result = "(";
+	for (size_t i = 0; i < N; i++) {
+		if (TypeConverter<float, String>::Convert(p.values[i] * multiplier, tmp))
+			result += tmp;
+		if (!unit.empty() && (!only_unit_on_last_value || (i == N - 1)))
+			result += unit;
+		if (i != N - 1) result += ", ";
+	}
+	result += ")";
+	return result;
+}
+
+template<size_t N>
+inline String ToString(const Transforms::UnresolvedPrimitive<N> & p) noexcept {
+	String result = "(";
+	for (size_t i = 0; i < N; i++) {
+		result += p.values[i].ToString();
+		if (i != N - 1) result += ", ";
+	}
+	result += ")";
+	return result;
+}
+
+
+
+String ToString(const Transforms::Matrix2D & p) noexcept { return "matrix" + ToString(static_cast<const Transforms::ResolvedPrimitive< 6 >&>(p), ""); }
+String ToString(const Transforms::Matrix3D & p) noexcept { return "matrix3d" + ToString(static_cast<const Transforms::ResolvedPrimitive< 16 >&>(p), ""); }
+String ToString(const Transforms::TranslateX & p) noexcept { return "translateX" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
+String ToString(const Transforms::TranslateY & p) noexcept { return "translateY" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
+String ToString(const Transforms::TranslateZ & p) noexcept { return "translateZ" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
+String ToString(const Transforms::Translate2D & p) noexcept { return "translate" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 2 >&>(p)); }
+String ToString(const Transforms::Translate3D & p) noexcept { return "translate3d" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 3 >&>(p)); }
+String ToString(const Transforms::ScaleX & p) noexcept { return "scaleX" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), ""); }
+String ToString(const Transforms::ScaleY & p) noexcept { return "scaleY" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), ""); }
+String ToString(const Transforms::ScaleZ & p) noexcept { return "scaleZ" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), ""); }
+String ToString(const Transforms::Scale2D & p) noexcept { return "scale" + ToString(static_cast<const Transforms::ResolvedPrimitive< 2 >&>(p), ""); }
+String ToString(const Transforms::Scale3D & p) noexcept { return "scale3d" + ToString(static_cast<const Transforms::ResolvedPrimitive< 3 >&>(p), ""); }
+String ToString(const Transforms::RotateX & p) noexcept { return "rotateX" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
+String ToString(const Transforms::RotateY & p) noexcept { return "rotateY" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
+String ToString(const Transforms::RotateZ & p) noexcept { return "rotateZ" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
+String ToString(const Transforms::Rotate2D & p) noexcept { return "rotate" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
+String ToString(const Transforms::Rotate3D & p) noexcept { return "rotate3d" + ToString(static_cast<const Transforms::ResolvedPrimitive< 4 >&>(p), "deg", true, true); }
+String ToString(const Transforms::SkewX & p) noexcept { return "skewX" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
+String ToString(const Transforms::SkewY & p) noexcept { return "skewY" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
+String ToString(const Transforms::Skew2D & p) noexcept { return "skew" + ToString(static_cast<const Transforms::ResolvedPrimitive< 2 >&>(p), "deg", true); }
+String ToString(const Transforms::Perspective & p) noexcept { return "perspective" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
+String ToString(const Transforms::DecomposedMatrix4& p) noexcept { return "decomposedMatrix3d"; }
+
+
 struct ToStringVisitor
 {
-	template <typename T>
-	String operator()(T& p0)
+	String run(const PrimitiveVariant& variant)
 	{
-		return p0.ToString();
+		switch (variant.type)
+		{
+		case PrimitiveVariant::MATRIX2D: return ToString(variant.matrix_2d);
+		case PrimitiveVariant::MATRIX3D: return ToString(variant.matrix_3d);
+		case PrimitiveVariant::TRANSLATEX: return ToString(variant.translate_x);
+		case PrimitiveVariant::TRANSLATEY: return ToString(variant.translate_y);
+		case PrimitiveVariant::TRANSLATEZ: return ToString(variant.translate_z);
+		case PrimitiveVariant::TRANSLATE2D: return ToString(variant.translate_2d);
+		case PrimitiveVariant::TRANSLATE3D: return ToString(variant.translate_3d);
+		case PrimitiveVariant::SCALEX: return ToString(variant.scale_x);
+		case PrimitiveVariant::SCALEY: return ToString(variant.scale_y);
+		case PrimitiveVariant::SCALEZ: return ToString(variant.scale_z);
+		case PrimitiveVariant::SCALE2D: return ToString(variant.scale_2d);
+		case PrimitiveVariant::SCALE3D: return ToString(variant.scale_3d);
+		case PrimitiveVariant::ROTATEX: return ToString(variant.rotate_x);
+		case PrimitiveVariant::ROTATEY: return ToString(variant.rotate_y);
+		case PrimitiveVariant::ROTATEZ: return ToString(variant.rotate_z);
+		case PrimitiveVariant::ROTATE2D: return ToString(variant.rotate_2d);
+		case PrimitiveVariant::ROTATE3D: return ToString(variant.rotate_3d);
+		case PrimitiveVariant::SKEWX: return ToString(variant.skew_x);
+		case PrimitiveVariant::SKEWY: return ToString(variant.skew_y);
+		case PrimitiveVariant::SKEW2D: return ToString(variant.skew_2d);
+		case PrimitiveVariant::PERSPECTIVE: return ToString(variant.perspective);
+		case PrimitiveVariant::DECOMPOSEDMATRIX4: return ToString(variant.decomposed_matrix_4);
+		default:
+			break;
+		}
+		ROCKET_ASSERT(false);
+		return String();
 	}
 };
 
 String Primitive::ToString() const noexcept
 {
-	String result = std::visit(ToStringVisitor{}, primitive);
+	String result = ToStringVisitor{}.run(primitive);
 	return result;
 }
 

+ 0 - 1
Source/Core/TransformState.cpp

@@ -27,7 +27,6 @@
 
 #include "precompiled.h"
 #include "../../Include/Rocket/Core/TransformState.h"
-#include <cmath>
 
 namespace Rocket {
 namespace Core {

+ 0 - 1
Source/Core/ViewState.cpp

@@ -27,7 +27,6 @@
 
 #include "precompiled.h"
 #include "../../Include/Rocket/Core/ViewState.h"
-#include <cmath>
 
 namespace Rocket {
 namespace Core {

+ 3 - 1
Source/Debugger/ElementInfo.cpp

@@ -285,8 +285,10 @@ void ElementInfo::UpdateSourceElement()
 				}
 			}
 
-			for(const auto& [name, variant] : source_element->GetAttributes())
+			for(const auto& pair : source_element->GetAttributes())
 			{
+				auto& name = pair.first;
+				auto& variant = pair.second;
 				Core::String value = variant.Get<Core::String>();
 				if(name != "class" && name != "style" && name != "id") 
 					attributes += Core::CreateString(name.size() + value.size() + 32, "%s: <em>%s</em><br />", name.c_str(), value.c_str());

+ 36 - 31
readme.md

@@ -1,13 +1,39 @@
-# libRocket - The HTML/CSS User Interface Library
+# RmlUi - The HTML/CSS User Interface Library Evolved
 
-Documentation at https://barotto.github.io/libRocketDoc/
+![RmlUi](https://github.com/mikke89/RmlUiDoc/raw/cc01edd834b003df6c649967bfd552bb0acc3d1e/assets/rmlui.png)
 
-Original website at http://librocket.com
+RmlUi - now with added boosters taking control of the rocket, targeting *your* games and applications.
 
+---
 
-## Fork features
+[![Build Status](https://travis-ci.com/mikke89/RmlUi.svg?branch=performance)](https://travis-ci.com/mikke89/RmlUi) [![Build status](https://ci.appveyor.com/api/projects/status/x95oi8mrb001pqhh/branch/performance?svg=true)](https://ci.appveyor.com/project/mikke89/rmlui/branch/performance)
 
-This fork contains some additional features over the [original libRocket branch](https://github.com/libRocket/libRocket), briefly documented here. Some of the new features utilize features from C++17, thus, a C++17-compliant compiler should be used.
+RmlUi is the C++ user interface package based on the HTML and CSS standards, designed as a complete solution for any project's interface needs. It is a fork of the [libRocket](https://github.com/libRocket/libRocket) project, introducing new features, bug fixes, and performance improvements. 
+
+RmlUi uses the time-tested open standards XHTML1.0 and CSS2.0 while borrowing features from HTML5 and CSS3, and extends them with features suited towards real-time applications. Because of this, you don't have to learn a whole new proprietary technology like other libraries in this space.
+
+Documentation is located at https://mikke89.github.io/RmlUiDoc/
+
+## Features
+
+- Cross platform architecture: Windows, macOS, Linux, iOS, etc.
+- Dynamic layout system.
+- Full animation and transform support.
+- Efficient application-wide styling, with a custom-built templating engine.
+- Fully featured control set: buttons, sliders, drop-downs, etc.
+- Runtime visual debugging suite.
+- Easily integrated and extensible with Lua ~~or Python~~ scripting.
+
+## Extensible
+
+- Abstracted interfaces for plugging in to any game engine.
+- Decorator engine allowing custom application-specific effects that can be applied to any element.
+- Generic event system that binds seamlessly into existing projects.
+
+
+## RmlUi features
+
+RmlUi introduces several features over the [original libRocket branch](https://github.com/libRocket/libRocket). While the [official RmlUi documentation](https://mikke89.github.io/RmlUiDoc/) is being updated with new documentation, some of the new features are also briefly documented here. Pull requests are welcome for improving the documentation at the [RmlUi documentation repository](https://github.com/mikke89/RmlUiDoc).
 
 
 ## Breaking changes
@@ -20,6 +46,7 @@ If upgrading from the original libRocket branch, some breaking changes should be
 - Removed RenderInterface::GetPixelsPerInch, instead the pixels per inch value has been fixed to 96 PPI, as per CSS specs. To achieve a scalable user interface, instead use the 'dp' unit.
 - Removed 'top' and 'bottom' from z-index property.
 
+
 ## Performance
 
 Users moving to this fork should generally see a substantial performance increase. 
@@ -27,7 +54,7 @@ Users moving to this fork should generally see a substantial performance increas
 - The update loop has been reworked to avoid doing unnecessary, repeated calculations whenever the document or style is changed. Instead of immediately updating properties on any affected elements, most of this work is done during the Context::Update call in a more carefully chosen order. Note that for this reason, when querying the Rocket API for properties such as size or position, this information may not be up-to-date with changes since the last Context::Update, such as newly added elements or classes. If this information is needed immediately, a call to ElementDocument::UpdateDocument can be made before such queries at a performance penalty.
 - Several containers have been replaced, such as std::map to [robin_hood::unordered_flat_map](https://github.com/martinus/robin-hood-hashing).
 - Reduced number of allocations and unnecessary recursive calls.
-- And many more, smaller optimizations, resulting in more than 4x performance increase for creation and destruction of a large number of elements. A benchmark for this is located in the animation sample for now.
+- And many more, smaller optimizations, resulting in more than 5x performance increase for creation and destruction of a large number of elements. A benchmark for this is located in the animation sample for now.
 
 
 ## Transform property
@@ -148,8 +175,9 @@ Internally, animations apply their properties on the local style of the element.
 
 Animations currently support full interpolation of transforms, largely following the CSS specifications. Additionally, interpolation support for colors, numbers, lengths, and percentages are implemented.
 
-Animations are very powerful coupled with transforms. See the animation sample project for more examples and details.
+Animations currently support full interpolation of transforms, largely following the CSS specifications. Additionally, interpolation is supported for colors, numbers, lengths, and percentages.
 
+Animations are very powerful coupled with transforms. See the animation sample project for more examples and details. There are also some [video demonstrations](https://mikke89.github.io/RmlUiDoc/pages/rmlui_features.html) of these features in the documentation.
 
 
 ## Transitions
@@ -242,32 +270,9 @@ border: 4px #e99;
 The slider on the `input.range` element can be dragged from anywhere in the element. Additionally, the `:checked` pseudo class can be used to style the selected item in drop-down lists.
 
 
-
-# libRocket
-
-libRocket is the C++ user interface package based on the HTML and CSS standards. It is 
-designed as a complete solution for any project's interface needs.
-
-libRocket uses the time-tested open standards XHTML1.0 and CSS2.0 (while borrowing features from 
-HTML5 and CSS3), and extends them with features suited towards real-time applications. Because of 
-this, you don't have to learn a whole new proprietary technology like other libraries in this space.
-
-## Features
-
-- Cross platform architecture: Windows, Mac, Linux, iPhone, etc.
-- Dynamic layout system.
-- Efficient application-wide styling, with a custom-built templating engine.
-- Fully featured control set: buttons, sliders, drop-downs, etc.
-- Runtime visual debugging suite.
-- Easily integrated and extensible with Python or Lua scripting.
-
-## Extensible
-- Abstracted interfaces for plugging in to any game engine.
-- Decorator engine allowing custom application-specific effects that can be applied to any element.
-- Generic event system that binds seamlessly into existing projects.
-
 ## License (MIT)
  
+ Copyright (c) 2019 The RmlUi Team, and contributors\
  Copyright (c) 2008-2014 CodePoint Ltd, Shift Technology Ltd, and contributors
  
  Permission is hereby granted, free of charge, to any person obtaining a copy