Browse Source

Merge branch 'high_dpi'

Michael Ragazzon 4 years ago
parent
commit
04fb41fa0b
100 changed files with 895 additions and 720 deletions
  1. 4 0
      CMake/FileList.cmake
  2. 2 2
      Include/RmlUi/Core/ComputedValues.h
  3. 11 0
      Include/RmlUi/Core/Context.h
  4. 0 5
      Include/RmlUi/Core/Decorator.h
  5. 11 1
      Include/RmlUi/Core/DecoratorInstancer.h
  6. 9 1
      Include/RmlUi/Core/Element.h
  7. 1 4
      Include/RmlUi/Core/ElementDocument.h
  8. 1 0
      Include/RmlUi/Core/ID.h
  9. 8 0
      Include/RmlUi/Core/Math.h
  10. 8 8
      Include/RmlUi/Core/Spritesheet.h
  11. 11 17
      Include/RmlUi/Core/StyleSheet.h
  12. 4 9
      Include/RmlUi/Core/StyleSheetContainer.h
  13. 17 5
      Include/RmlUi/Core/StyleSheetTypes.h
  14. 2 7
      Include/RmlUi/Core/Types.h
  15. 2 2
      Samples/assets/demo.rml
  16. 112 109
      Samples/assets/invader.rcss
  17. 1 1
      Samples/assets/window.rml
  18. 30 28
      Samples/basic/animation/data/animation.rml
  19. 9 14
      Samples/basic/animation/src/main.cpp
  20. 10 9
      Samples/basic/benchmark/data/benchmark.rml
  21. 3 5
      Samples/basic/benchmark/src/main.cpp
  22. 1 1
      Samples/basic/bitmapfont/src/main.cpp
  23. 1 1
      Samples/basic/customlog/src/main.cpp
  24. 27 25
      Samples/basic/databinding/data/databinding.rml
  25. 3 10
      Samples/basic/databinding/src/main.cpp
  26. 142 140
      Samples/basic/demo/data/demo.rml
  27. 6 12
      Samples/basic/demo/src/main.cpp
  28. 8 8
      Samples/basic/drag/data/icon.rcss
  29. 2 2
      Samples/basic/drag/data/inventory.rml
  30. 2 2
      Samples/basic/drag/src/Inventory.cpp
  31. 1 1
      Samples/basic/drag/src/main.cpp
  32. 1 1
      Samples/basic/loaddocument/src/main.cpp
  33. 2 2
      Samples/basic/lottie/data/lottie.rml
  34. 1 1
      Samples/basic/lottie/src/main.cpp
  35. 26 25
      Samples/basic/transform/data/transform.rml
  36. 5 5
      Samples/basic/transform/src/main.cpp
  37. 6 6
      Samples/basic/treeview/data/treeview.rml
  38. 1 1
      Samples/basic/treeview/src/main.cpp
  39. 14 14
      Samples/invaders/data/game.rml
  40. 5 5
      Samples/invaders/data/help.rml
  41. 10 10
      Samples/invaders/data/high_score.rml
  42. 2 2
      Samples/invaders/data/logo.rml
  43. 2 2
      Samples/invaders/data/main_menu.rml
  44. 3 3
      Samples/invaders/data/options.rml
  45. 2 2
      Samples/invaders/data/pause.rml
  46. 6 6
      Samples/invaders/data/start_game.rml
  47. 2 2
      Samples/invaders/src/DecoratorDefender.cpp
  48. 1 1
      Samples/invaders/src/DecoratorDefender.h
  49. 3 5
      Samples/invaders/src/DecoratorInstancerDefender.cpp
  50. 3 3
      Samples/invaders/src/Defender.cpp
  51. 1 1
      Samples/invaders/src/Defender.h
  52. 2 1
      Samples/invaders/src/ElementGame.cpp
  53. 4 4
      Samples/invaders/src/Game.cpp
  54. 1 1
      Samples/invaders/src/Game.h
  55. 3 3
      Samples/invaders/src/Invader.cpp
  56. 1 1
      Samples/invaders/src/Invader.h
  57. 6 3
      Samples/invaders/src/Shield.cpp
  58. 1 1
      Samples/invaders/src/Shield.h
  59. 10 4
      Samples/invaders/src/Sprite.cpp
  60. 1 1
      Samples/invaders/src/Sprite.h
  61. 1 1
      Samples/invaders/src/main.cpp
  62. 14 14
      Samples/luainvaders/data/game.rml
  63. 5 5
      Samples/luainvaders/data/help.rml
  64. 10 10
      Samples/luainvaders/data/high_score.rml
  65. 2 2
      Samples/luainvaders/data/logo.rml
  66. 2 2
      Samples/luainvaders/data/main_menu.rml
  67. 3 3
      Samples/luainvaders/data/options.rml
  68. 2 2
      Samples/luainvaders/data/pause.rml
  69. 6 6
      Samples/luainvaders/data/start_game.rml
  70. 1 1
      Samples/luainvaders/data/window.rml
  71. 2 2
      Samples/luainvaders/src/DecoratorDefender.cpp
  72. 1 1
      Samples/luainvaders/src/DecoratorDefender.h
  73. 3 5
      Samples/luainvaders/src/DecoratorInstancerDefender.cpp
  74. 3 3
      Samples/luainvaders/src/Defender.cpp
  75. 1 1
      Samples/luainvaders/src/Defender.h
  76. 2 1
      Samples/luainvaders/src/ElementGame.cpp
  77. 4 4
      Samples/luainvaders/src/Game.cpp
  78. 1 1
      Samples/luainvaders/src/Game.h
  79. 3 3
      Samples/luainvaders/src/Invader.cpp
  80. 1 1
      Samples/luainvaders/src/Invader.h
  81. 6 3
      Samples/luainvaders/src/Shield.cpp
  82. 1 1
      Samples/luainvaders/src/Shield.h
  83. 10 4
      Samples/luainvaders/src/Sprite.cpp
  84. 1 1
      Samples/luainvaders/src/Sprite.h
  85. 1 1
      Samples/luainvaders/src/main.cpp
  86. 3 4
      Samples/shell/include/Shell.h
  87. 2 7
      Samples/shell/include/ShellRenderInterfaceExtensions.h
  88. 0 2
      Samples/shell/include/ShellRenderInterfaceOpenGL.h
  89. 5 3
      Samples/shell/include/win32/IncludeWindows.h
  90. 1 1
      Samples/shell/src/ShellRenderInterfaceOpenGL.cpp
  91. 27 6
      Samples/shell/src/macosx/ShellMacOSX.cpp
  92. 0 11
      Samples/shell/src/macosx/ShellRenderInterfaceExtensionsOpenGL_MacOSX.cpp
  93. 20 4
      Samples/shell/src/win32/InputWin32.cpp
  94. 0 10
      Samples/shell/src/win32/ShellRenderInterfaceExtensionsOpenGL_Win32.cpp
  95. 119 6
      Samples/shell/src/win32/ShellWin32.cpp
  96. 0 11
      Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp
  97. 34 8
      Samples/shell/src/x11/ShellX11.cpp
  98. 18 18
      Samples/tutorial/datagrid/data/tutorial.rcss
  99. 4 4
      Samples/tutorial/datagrid/data/tutorial.rml
  100. 2 2
      Samples/tutorial/datagrid/src/DecoratorDefender.cpp

+ 4 - 0
CMake/FileList.cmake

@@ -74,6 +74,8 @@ set(Core_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertiesIterator.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertiesIterator.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserAnimation.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserAnimation.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserDecorator.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserFontEffect.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserRatio.h
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserRatio.h
@@ -352,6 +354,8 @@ set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyDictionary.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyDictionary.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserAnimation.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserAnimation.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserDecorator.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserFontEffect.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserRatio.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserRatio.cpp

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

@@ -214,8 +214,8 @@ struct ComputedValues
 	TransitionList transition;
 	TransitionList transition;
 	AnimationList animation;
 	AnimationList animation;
 
 
-	DecoratorsPtr decorator;
-	FontEffectsPtr font_effect; // Sorted by layer first (back then front), then by declaration order.
+	bool has_decorator = false;
+	bool has_font_effect = false;
 };
 };
 }
 }
 
 

+ 11 - 0
Include/RmlUi/Core/Context.h

@@ -115,6 +115,15 @@ public:
 	/// @param[in] show True to enable mouse cursor handling, false to disable.
 	/// @param[in] show True to enable mouse cursor handling, false to disable.
 	void EnableMouseCursor(bool enable);
 	void EnableMouseCursor(bool enable);
 
 
+	/// Activate or deactivate a media theme. Themes can be used in RCSS media queries.
+	/// @param theme_name[in] The name of the theme to (de)activate.
+	/// @param activate True to activate the given theme, false to deactivate.
+	void ActivateTheme(const String& theme_name, bool activate);
+	/// Check if a given media theme has been activated.
+	/// @param theme_name The name of the theme.
+	/// @return True if the theme is activated.
+	bool IsThemeActive(const String& theme_name) const;
+
 	/// Returns the first document in the context with the given id.
 	/// Returns the first document in the context with the given id.
 	/// @param[in] id The id of the desired document.
 	/// @param[in] id The id of the desired document.
 	/// @return The document (if it was found), or nullptr if no document exists with the ID.
 	/// @return The document (if it was found), or nullptr if no document exists with the ID.
@@ -265,6 +274,8 @@ private:
 	float density_independent_pixel_ratio;
 	float density_independent_pixel_ratio;
 	String documents_base_tag = "body";
 	String documents_base_tag = "body";
 
 
+	SmallUnorderedSet<String> active_themes;
+
 	ContextInstancer* instancer;
 	ContextInstancer* instancer;
 
 
 	using ElementSet = SmallOrderedSet< Element* >;
 	using ElementSet = SmallOrderedSet< Element* >;

+ 0 - 5
Include/RmlUi/Core/Decorator.h

@@ -70,11 +70,6 @@ public:
 	static const DecoratorDataHandle INVALID_DECORATORDATAHANDLE = 0;
 	static const DecoratorDataHandle INVALID_DECORATORDATAHANDLE = 0;
 
 
 protected:
 protected:
-	/// Attempts to load a texture into the list of textures in use by the decorator.
-	/// @param[in] texture_name The name of the texture to load.
-	/// @param[in] rcss_path The RCSS file the decorator definition was loaded from; this is used to resolve relative paths.
-	/// @return The index of the texture if the load was successful, or -1 if the load failed.
-	int LoadTexture(const String& texture_name, const String& rcss_path);
 	/// Adds a texture if it is valid into the list of textures in use by the decorator.
 	/// Adds a texture if it is valid into the list of textures in use by the decorator.
 	/// @param[in] texture The texture to add.
 	/// @param[in] texture The texture to add.
 	/// @return The index of the texture if it is successful, or -1 if it is invalid.
 	/// @return The index of the texture if it is successful, or -1 if it is invalid.

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

@@ -36,6 +36,7 @@
 namespace Rml {
 namespace Rml {
 
 
 struct Sprite;
 struct Sprite;
+struct Texture;
 class StyleSheet;
 class StyleSheet;
 class Decorator;
 class Decorator;
 class DecoratorInstancerInterface;
 class DecoratorInstancerInterface;
@@ -86,13 +87,22 @@ private:
 
 
 class RMLUICORE_API DecoratorInstancerInterface {
 class RMLUICORE_API DecoratorInstancerInterface {
 public:
 public:
-	DecoratorInstancerInterface(const StyleSheet& style_sheet) : style_sheet(style_sheet) {}
+	DecoratorInstancerInterface(const StyleSheet& style_sheet, const PropertySource* property_source) : style_sheet(style_sheet), property_source(property_source) {}
 
 
 	/// Get a sprite from any @spritesheet in the style sheet the decorator is being instanced on.
 	/// Get a sprite from any @spritesheet in the style sheet the decorator is being instanced on.
 	const Sprite* GetSprite(const String& name) const;
 	const Sprite* GetSprite(const String& name) const;
 
 
+	/// Get the texture from a filename set in the decorator property.
+	/// This will use the document path where the 'decorator' property was declared to locate relative files, if available.
+	Texture GetTexture(const String& filename) const;
+
+	/// Get the path from the texture from a filename set in the decorator property.
+	/// This will use the document path where the 'decorator' property was declared to locate relative files, if available.
+	const String& GetSourcePath(const String& filename) const;
+
 private:
 private:
 	const StyleSheet& style_sheet;
 	const StyleSheet& style_sheet;
+	const PropertySource* property_source;
 };
 };
 
 
 } // namespace Rml
 } // namespace Rml

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

@@ -416,7 +416,7 @@ public:
 	/// Gets this element's parent node.
 	/// Gets this element's parent node.
 	/// @return This element's parent.
 	/// @return This element's parent.
 	Element* GetParentNode() const;
 	Element* GetParentNode() const;
-	/// Recursively search for a ancestor of this node matching the given selector.
+	/// Recursively search for the first ancestor of this node matching the given selector.
 	/// @param[in] selectors The selector or comma-separated selectors to match against.
 	/// @param[in] selectors The selector or comma-separated selectors to match against.
 	/// @return The ancestor if found, or nullptr if no ancestor could be matched.
 	/// @return The ancestor if found, or nullptr if no ancestor could be matched.
 	/// @performance Prefer GetElementById/TagName/ClassName whenever possible.
 	/// @performance Prefer GetElementById/TagName/ClassName whenever possible.
@@ -605,6 +605,10 @@ protected:
 	virtual void OnResize();
 	virtual void OnResize();
 	/// Called during a layout operation, when the element is being positioned and sized.
 	/// Called during a layout operation, when the element is being positioned and sized.
 	virtual void OnLayout();
 	virtual void OnLayout();
+	/// Called when the 'dp'-ratio has been changed.
+	virtual void OnDpRatioChange();
+	/// Called when the current document's compiled style sheet has been changed. This may result in changed sprites.
+	virtual void OnStyleSheetChange();
 
 
 	/// Called when attributes on the element are changed.
 	/// Called when attributes on the element are changed.
 	/// @param[in] changed_attributes Dictionary of attributes changed on the element. Attribute value will be empty if it was unset.
 	/// @param[in] changed_attributes Dictionary of attributes changed on the element. Attribute value will be empty if it was unset.
@@ -642,6 +646,8 @@ protected:
 
 
 	void SetOwnerDocument(ElementDocument* document);
 	void SetOwnerDocument(ElementDocument* document);
 
 
+	void OnStyleSheetChangeRecursive();
+
 	void Release() override;
 	void Release() override;
 
 
 private:
 private:
@@ -664,6 +670,8 @@ private:
 	void DirtyTransformState(bool perspective_dirty, bool transform_dirty);
 	void DirtyTransformState(bool perspective_dirty, bool transform_dirty);
 	void UpdateTransformState();
 	void UpdateTransformState();
 
 
+	void OnDpRatioChangeRecursive();
+
 	/// Start an animation, replacing any existing animations of the same property name. If start_value is null, the element's current value is used.
 	/// Start an animation, replacing any existing animations of the same property name. If start_value is null, the element's current value is used.
 	ElementAnimationList::iterator StartAnimation(PropertyId property_id, const Property * start_value, int num_iterations, bool alternate_direction, float delay, bool initiated_by_animation_property);
 	ElementAnimationList::iterator StartAnimation(PropertyId property_id, const Property * start_value, int num_iterations, bool alternate_direction, float delay, bool initiated_by_animation_property);
 
 

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

@@ -160,11 +160,8 @@ private:
 	/// Returns true if the document has been marked as needing a re-layout.
 	/// Returns true if the document has been marked as needing a re-layout.
 	bool IsLayoutDirty() override;
 	bool IsLayoutDirty() override;
 
 
-	/// Notify the document that media query related properties have changed and that stylesheets need to be re-evaluated.
+	/// Notify the document that media query related properties have changed and that style sheets need to be re-evaluated.
 	void DirtyMediaQueries();
 	void DirtyMediaQueries();
-	
-	/// Updates all sizes defined by the 'dp' unit.
-	void DirtyDpProperties();
 
 
 	/// Updates all sizes defined by the 'vw' and the 'vh' units.
 	/// Updates all sizes defined by the 'vw' and the 'vh' units.
 	void DirtyVwAndVhProperties();
 	void DirtyVwAndVhProperties();

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

@@ -183,6 +183,7 @@ enum class MediaQueryId : uint8_t
 	MinResolution,
 	MinResolution,
 	MaxResolution,
 	MaxResolution,
 	Orientation,
 	Orientation,
+	Theme,
 
 
 	NumDefinedIds
 	NumDefinedIds
 };
 };

+ 8 - 0
Include/RmlUi/Core/Math.h

@@ -149,6 +149,14 @@ RMLUICORE_API float RoundFloat(float value);
 /// @param[in] value The value to round.
 /// @param[in] value The value to round.
 /// @return The rounded integer as double.
 /// @return The rounded integer as double.
 RMLUICORE_API double RoundFloat(double value);
 RMLUICORE_API double RoundFloat(double value);
+/// Rounds a floating-point value up to the nearest integer.
+/// @param[in] value The value to round.
+/// @return The rounded integer as float.
+RMLUICORE_API float RoundUpFloat(float value);
+/// Rounds a floating-point value down to the nearest integer.
+/// @param[in] value The value to round.
+/// @return The rounded integer as float.
+RMLUICORE_API float RoundDownFloat(float value);
 /// Rounds a floating-point value to the nearest integer.
 /// Rounds a floating-point value to the nearest integer.
 /// @param[in] value The value to round.
 /// @param[in] value The value to round.
 /// @return The rounded integer.
 /// @return The rounded integer.

+ 8 - 8
Include/RmlUi/Core/Spritesheet.h

@@ -56,14 +56,13 @@ struct Spritesheet {
 	String image_source;
 	String image_source;
 	String definition_source;
 	String definition_source;
 	int definition_line_number;
 	int definition_line_number;
+	float display_scale; // The inverse of the 'resolution' spritesheet property.
 	Texture texture;
 	Texture texture;
-	StringList sprite_names;
 
 
-	Spritesheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, const Texture& texture)
-		: name(name), image_source(image_source), definition_source(definition_source), definition_line_number(definition_line_number), texture(texture) {}
+	Spritesheet(const String& name, const String& image_source, const String& definition_source,
+		int definition_line_number, float display_scale, const Texture& texture);
 };
 };
 
 
-using SpritesheetMap = SmallUnorderedMap<String, SharedPtr<const Spritesheet>>; // key: spritesheet name (as given in @spritesheet)
 using SpriteDefinitionList = Vector<Pair<String, Rectangle>>; // Sprite name and rectangle
 using SpriteDefinitionList = Vector<Pair<String, Rectangle>>; // Sprite name and rectangle
 
 
 
 
@@ -73,23 +72,24 @@ using SpriteDefinitionList = Vector<Pair<String, Rectangle>>; // Sprite name and
 class SpritesheetList {
 class SpritesheetList {
 public:
 public:
 	/// Adds a new sprite sheet to the list and inserts all sprites with unique names into the global list.
 	/// Adds a new sprite sheet to the list and inserts all sprites with unique names into the global list.
-	bool AddSpriteSheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, const SpriteDefinitionList& sprite_definitions);
+	bool AddSpriteSheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, float display_scale, const SpriteDefinitionList& sprite_definitions);
 
 
 	/// Get a sprite from its name if it exists.
 	/// Get a sprite from its name if it exists.
 	/// Note: The pointer is invalidated whenever another sprite is added. Do not store it around.
 	/// Note: The pointer is invalidated whenever another sprite is added. Do not store it around.
 	const Sprite* GetSprite(const String& name) const;
 	const Sprite* GetSprite(const String& name) const;
 
 
-	/// Merge 'other' into this.
+	/// Merge 'other' into this. Sprites in 'other' will overwrite local sprites if they share the same name.
 	void Merge(const SpritesheetList& other);
 	void Merge(const SpritesheetList& other);
 
 
 	void Reserve(size_t size_sprite_sheets, size_t size_sprites);
 	void Reserve(size_t size_sprite_sheets, size_t size_sprites);
 	size_t NumSpriteSheets() const;
 	size_t NumSpriteSheets() const;
 	size_t NumSprites() const;
 	size_t NumSprites() const;
 
 
-	String ToString() const;
 
 
 private:
 private:
-	SpritesheetMap spritesheet_map;
+	using Spritesheets = Vector<SharedPtr<const Spritesheet>>;
+
+	Spritesheets spritesheets;
 	SpriteMap sprite_map;
 	SpriteMap sprite_map;
 };
 };
 
 

+ 11 - 17
Include/RmlUi/Core/StyleSheet.h

@@ -45,6 +45,7 @@ class SpritesheetList;
 class Stream;
 class Stream;
 class StyleSheetContainer;
 class StyleSheetContainer;
 class StyleSheetParser;
 class StyleSheetParser;
+struct PropertySource;
 struct Sprite;
 struct Sprite;
 struct Spritesheet;
 struct Spritesheet;
 
 
@@ -65,26 +66,16 @@ public:
 
 
 	/// Combines this style sheet with another one, producing a new sheet.
 	/// Combines this style sheet with another one, producing a new sheet.
 	UniquePtr<StyleSheet> CombineStyleSheet(const StyleSheet& sheet) const;
 	UniquePtr<StyleSheet> CombineStyleSheet(const StyleSheet& sheet) const;
-
-	/// Creates an exact copy of this style sheet.
-	UniquePtr<StyleSheet> Clone() const;
+	/// Merges another style sheet into this.
+	void MergeStyleSheet(const StyleSheet& sheet);
 
 
 	/// Builds the node index for a combined style sheet.
 	/// Builds the node index for a combined style sheet.
 	void BuildNodeIndex();
 	void BuildNodeIndex();
-	/// Optimizes some properties for faster retrieval.
-	/// Specifically, converts all decorator and font-effect properties from strings to instanced decorator and font effect lists.
-	void OptimizeNodeProperties();
 
 
 	/// Returns the Keyframes of the given name, or null if it does not exist.
 	/// Returns the Keyframes of the given name, or null if it does not exist.
 	/// @lifetime The returned pointer becomes invalidated whenever the style sheet is re-generated. Do not store this pointer or references to subobjects around.
 	/// @lifetime The returned pointer becomes invalidated whenever the style sheet is re-generated. Do not store this pointer or references to subobjects around.
 	const Keyframes* GetKeyframes(const String& name) const;
 	const Keyframes* GetKeyframes(const String& name) const;
 
 
-	/// Parses the decorator property from a string and returns a list of instanced decorators.
-	DecoratorsPtr InstanceDecoratorsFromString(const String& decorator_string_value, const SharedPtr<const PropertySource>& source) const;
-
-	/// Parses the font-effect property from a string and returns a list of instanced font-effects.
-	FontEffectsPtr InstanceFontEffectsFromString(const String& font_effect_string_value, const SharedPtr<const PropertySource>& source) const;
-
 	/// Get sprite located in any spritesheet within this stylesheet.
 	/// Get sprite located in any spritesheet within this stylesheet.
 	/// @lifetime The returned pointer becomes invalidated whenever the style sheet is re-generated. Do not store this pointer or references to subobjects around.
 	/// @lifetime The returned pointer becomes invalidated whenever the style sheet is re-generated. Do not store this pointer or references to subobjects around.
 	const Sprite* GetSprite(const String& name) const;
 	const Sprite* GetSprite(const String& name) const;
@@ -95,14 +86,12 @@ public:
 	/// Retrieve the hash key used to look-up applicable nodes in the node index.
 	/// Retrieve the hash key used to look-up applicable nodes in the node index.
 	static size_t NodeHash(const String& tag, const String& id);
 	static size_t NodeHash(const String& tag, const String& id);
 
 
+	/// Returns a list of instanced decorators from the declarations. The instances are cached for faster future retrieval.
+	const Vector<SharedPtr<const Decorator>>& InstanceDecorators(const DecoratorDeclarationList& declaration_list, const PropertySource* decorator_source) const;
+
 private:
 private:
 	StyleSheet();
 	StyleSheet();
 
 
-	using ElementDefinitionCache = UnorderedMap< size_t, SharedPtr<ElementDefinition> >;
-
-	/// Returns the Decorator of the given name, or null if it does not exist.
-	SharedPtr<Decorator> GetDecorator(const String& name) const;
-	
 	// Root level node, attributes from special nodes like "body" get added to this node
 	// Root level node, attributes from special nodes like "body" get added to this node
 	UniquePtr<StyleSheetNode> root;
 	UniquePtr<StyleSheetNode> root;
 
 
@@ -126,8 +115,13 @@ private:
 	NodeIndex styled_node_index;
 	NodeIndex styled_node_index;
 
 
 	// Index of node sets to element definitions.
 	// Index of node sets to element definitions.
+	using ElementDefinitionCache = UnorderedMap< size_t, SharedPtr<ElementDefinition> >;
 	mutable ElementDefinitionCache node_cache;
 	mutable ElementDefinitionCache node_cache;
 
 
+	// Cached decorator instances.
+	using DecoratorCache = UnorderedMap< String, Vector<SharedPtr<const Decorator>> >;
+	mutable DecoratorCache decorator_cache;
+
 	friend Rml::StyleSheetParser;
 	friend Rml::StyleSheetParser;
 	friend Rml::StyleSheetContainer;
 	friend Rml::StyleSheetContainer;
 };
 };

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

@@ -30,7 +30,6 @@
 #define RMLUI_CORE_STYLESHEETCONTAINER_H
 #define RMLUI_CORE_STYLESHEETCONTAINER_H
 
 
 #include "Traits.h"
 #include "Traits.h"
-#include "PropertyDictionary.h"
 #include "StyleSheetTypes.h"
 #include "StyleSheetTypes.h"
 
 
 namespace Rml {
 namespace Rml {
@@ -54,12 +53,11 @@ public:
 	/// Loads a style from a CSS definition.
 	/// Loads a style from a CSS definition.
 	bool LoadStyleSheetContainer(Stream* stream, int begin_line_number = 1);
 	bool LoadStyleSheetContainer(Stream* stream, int begin_line_number = 1);
 
 
-	/// Compiles a single style sheet by combining all contained style sheets whose media queries match the provided parameters.
-	/// @param[in] dp_ratio The current context ratio of 'dp' units to 'px' units
-	/// @param[in] vp_dimensions The current context viewport dimensions
+	/// Compiles a single style sheet by combining all contained style sheets whose media queries match the current state of the context.
+	/// @param[in] context The current context used for evaluating media query parameters against.
 	/// @returns True when the compiled style sheet was changed, otherwise false.
 	/// @returns True when the compiled style sheet was changed, otherwise false.
 	/// @warning This operation invalidates all references to the previously compiled style sheet.
 	/// @warning This operation invalidates all references to the previously compiled style sheet.
-	bool UpdateCompiledStyleSheet(float dp_ratio, Vector2f vp_dimensions);
+	bool UpdateCompiledStyleSheet(const Context* context);
 
 
 	/// Returns the previously compiled style sheet. 
 	/// Returns the previously compiled style sheet. 
 	StyleSheet* GetCompiledStyleSheet();
 	StyleSheet* GetCompiledStyleSheet();
@@ -70,11 +68,8 @@ public:
 	/// Merge another style sheet container into this.
 	/// Merge another style sheet container into this.
 	void MergeStyleSheetContainer(const StyleSheetContainer& container);
 	void MergeStyleSheetContainer(const StyleSheetContainer& container);
 
 
-	/// Optimizes properties of the underlying style sheet(s) for faster retrieval.
-	void OptimizeNodeProperties();
-
 private:
 private:
-	Vector<MediaBlock> media_blocks;
+	MediaBlockList media_blocks;
 
 
 	StyleSheet* compiled_style_sheet = nullptr;
 	StyleSheet* compiled_style_sheet = nullptr;
 	UniquePtr<StyleSheet> combined_compiled_style_sheet;
 	UniquePtr<StyleSheet> combined_compiled_style_sheet;

+ 17 - 5
Include/RmlUi/Core/StyleSheetTypes.h

@@ -29,12 +29,13 @@
 #ifndef RMLUI_CORE_STYLESHEETTYPES_H
 #ifndef RMLUI_CORE_STYLESHEETTYPES_H
 #define RMLUI_CORE_STYLESHEETTYPES_H
 #define RMLUI_CORE_STYLESHEETTYPES_H
 
 
-#include "Traits.h"
+#include "Types.h"
 #include "PropertyDictionary.h"
 #include "PropertyDictionary.h"
-#include "Spritesheet.h"
 
 
 namespace Rml {
 namespace Rml {
 
 
+class Decorator;
+class DecoratorInstancer;
 class StyleSheet;
 class StyleSheet;
 
 
 struct KeyframeBlock {
 struct KeyframeBlock {
@@ -55,13 +56,24 @@ struct DecoratorSpecification {
 };
 };
 using DecoratorSpecificationMap = UnorderedMap<String, DecoratorSpecification>;
 using DecoratorSpecificationMap = UnorderedMap<String, DecoratorSpecification>;
 
 
+struct DecoratorDeclaration {
+	String type;
+	DecoratorInstancer* instancer;
+	PropertyDictionary properties;
+};
+struct DecoratorDeclarationList {
+	Vector<DecoratorDeclaration> list;
+	String value;
+};
+
 struct MediaBlock {
 struct MediaBlock {
 	MediaBlock() {}
 	MediaBlock() {}
-	MediaBlock(PropertyDictionary _properties, UniquePtr<StyleSheet> _stylesheet) : properties(std::move(_properties)), stylesheet(std::move(_stylesheet)) {}
+	MediaBlock(PropertyDictionary _properties, SharedPtr<StyleSheet> _stylesheet) : properties(std::move(_properties)), stylesheet(std::move(_stylesheet)) {}
 
 
-	PropertyDictionary properties;
-	UniquePtr<StyleSheet> stylesheet;
+	PropertyDictionary properties; // Media query properties
+	SharedPtr<StyleSheet> stylesheet;
 };
 };
+using MediaBlockList = Vector<MediaBlock>;
 
 
 } // namespace Rml
 } // namespace Rml
 #endif
 #endif

+ 2 - 7
Include/RmlUi/Core/Types.h

@@ -85,6 +85,7 @@ class FontEffect;
 struct Animation;
 struct Animation;
 struct Transition;
 struct Transition;
 struct TransitionList;
 struct TransitionList;
+struct DecoratorDeclarationList;
 struct Rectangle;
 struct Rectangle;
 enum class EventId : uint16_t;
 enum class EventId : uint16_t;
 enum class PropertyId : uint8_t;
 enum class PropertyId : uint8_t;
@@ -117,13 +118,7 @@ using ElementAttributes = Dictionary;
 using XMLAttributes = Dictionary;
 using XMLAttributes = Dictionary;
 
 
 using AnimationList = Vector<Animation>;
 using AnimationList = Vector<Animation>;
-using DecoratorList = Vector<SharedPtr<const Decorator>>;
 using FontEffectList = Vector<SharedPtr<const FontEffect>>;
 using FontEffectList = Vector<SharedPtr<const FontEffect>>;
-
-struct Decorators {
-	DecoratorList list;
-	String value;
-};
 struct FontEffects {
 struct FontEffects {
 	FontEffectList list;
 	FontEffectList list;
 	String value;
 	String value;
@@ -131,7 +126,7 @@ struct FontEffects {
 
 
 // Additional smart pointers
 // Additional smart pointers
 using TransformPtr = SharedPtr< Transform >;
 using TransformPtr = SharedPtr< Transform >;
-using DecoratorsPtr = SharedPtr<const Decorators>;
+using DecoratorsPtr = SharedPtr<const DecoratorDeclarationList>;
 using FontEffectsPtr = SharedPtr<const FontEffects>;
 using FontEffectsPtr = SharedPtr<const FontEffects>;
 
 
 // Data binding types
 // Data binding types

+ 2 - 2
Samples/assets/demo.rml

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 300px;
-				height: 225px;
+				width: 300dp;
+				height: 225dp;
 				
 				
 				margin: auto;
 				margin: auto;
 			}
 			}

+ 112 - 109
Samples/assets/invader.rcss

@@ -2,10 +2,13 @@
 {
 {
 	src: invader.tga;
 	src: invader.tga;
 	
 	
+	/* For high dpi screens, designates the scaling it is intended to be shown at. */
+	resolution: 1x;  
+	
 	/**
 	/**
 	   The following specifies a list of sprite names and associated rectangles into the image given above.
 	   The following specifies a list of sprite names and associated rectangles into the image given above.
 	   Any sprite given here can be specified in a decorator. Their names must be globally unique.
 	   Any sprite given here can be specified in a decorator. Their names must be globally unique.
-	   Rectangles are specified as: x y width height.
+	   Rectangles are specified as: x y width height. With the origin assumed to be at the top left corner.
 	*/
 	*/
 	title-bar-l: 147px 0px 82px 85px;
 	title-bar-l: 147px 0px 82px 85px;
 	title-bar-c: 229px 0px  1px 85px;
 	title-bar-c: 229px 0px  1px 85px;
@@ -45,7 +48,7 @@
 	
 	
 	text-l: 162px 192px 14px 31px;
 	text-l: 162px 192px 14px 31px;
 	text-c: 176px 192px 1px 31px;
 	text-c: 176px 192px 1px 31px;
-	textarea: 162px 192px 145px 31px;
+	textarea: 162px 193px 145px 31px;
 	textarea-inner: 173px 206px 127px 10px;
 	textarea-inner: 173px 206px 127px 10px;
 	
 	
 	selectbox-tl: 281px 275px 11px 9px;
 	selectbox-tl: 281px 275px 11px 9px;
@@ -135,20 +138,20 @@ body
 	font-family: LatoLatin;
 	font-family: LatoLatin;
 	font-weight: normal;
 	font-weight: normal;
 	font-style: normal;
 	font-style: normal;
-	font-size: 15px;
+	font-size: 15dp;
 	color: white;
 	color: white;
 }
 }
 
 
 body.window
 body.window
 {
 {
-	padding-top: 43px;
-	padding-bottom: 20px;
+	padding-top: 43dp;
+	padding-bottom: 20dp;
 	
 	
-	min-width: 250px;
-	max-width: 800px;
+	min-width: 250dp;
+	max-width: 800dp;
 	
 	
-	min-height: 135px;
-	max-height: 700px;
+	min-height: 135dp;
+	max-height: 700dp;
 }
 }
 
 
 div#title_bar
 div#title_bar
@@ -156,8 +159,8 @@ div#title_bar
 	z-index: 1;
 	z-index: 1;
 
 
 	position: absolute;
 	position: absolute;
-	top: 3px;
-	left: 0px;
+	top: 3dp;
+	left: 0;
 	
 	
 	text-align: left;
 	text-align: left;
 }
 }
@@ -165,25 +168,25 @@ div#title_bar
 div#title_bar div#icon
 div#title_bar div#icon
 {
 {
 	position: absolute;
 	position: absolute;
-	left: 20px;
-	top: 2px;
+	left: 20dp;
+	top: 2dp;
 	
 	
-	width: 51px;
-	height: 39px;
+	width: 51dp;
+	height: 39dp;
 }
 }
 
 
 
 
 div#title_bar span
 div#title_bar span
 {
 {
-	padding-left: 85px;
-	padding-right: 25px;
-	padding-top: 17px;
-	padding-bottom: 51px;
+	padding-left: 85dp;
+	padding-right: 25dp;
+	padding-top: 17dp;
+	padding-bottom: 51dp;
 
 
-	font-size: 20px;
+	font-size: 20dp;
 	font-weight: bold;
 	font-weight: bold;
 	
 	
-	font-effect: glow(2px 2px 0px 1px #1117);
+	font-effect: glow(1dp black);
 
 
 	decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
 	decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
 }
 }
@@ -191,7 +194,7 @@ div#title_bar span
 div#window
 div#window
 {
 {
 	width: auto;
 	width: auto;
-	padding: 10px 15px;
+	padding: 10dp 15dp;
 	
 	
 	decorator: tiled-box(
 	decorator: tiled-box(
 		window-tl, window-t, window-tr, 
 		window-tl, window-t, window-tr, 
@@ -226,10 +229,10 @@ h1
 	margin-bottom: 0.4em;
 	margin-bottom: 0.4em;
 
 
 	text-align: left;
 	text-align: left;
-	font-size: 16px;
+	font-size: 16dp;
 	font-weight: bold;
 	font-weight: bold;
 
 
-	font-effect: glow(1px 1px 1px 1px #1117);
+	font-effect: glow(1dp 1dp 1dp 1dp #1117);
 }
 }
 
 
 
 
@@ -238,12 +241,12 @@ input,
 select,
 select,
 dataselect
 dataselect
 {
 {
-	margin-left: 20px;
+	margin-left: 20dp;
 }
 }
 
 
 input.submit
 input.submit
 {
 {
-	margin-left: 0px;
+	margin-left: 0;
 }
 }
 
 
 
 
@@ -253,13 +256,13 @@ input.submit
 {
 {
 	display: inline-block;
 	display: inline-block;
 
 
-	width: 159px;
-	height: 35px;
+	width: 159dp;
+	height: 35dp;
 
 
-	padding-top: 10px;
-	vertical-align: -18px;
+	padding-top: 10dp;
+	vertical-align: -18dp;
 
 
-	font-size: 16px;
+	font-size: 16dp;
 	text-align: center;
 	text-align: center;
 	tab-index: auto;
 	tab-index: auto;
 
 
@@ -269,7 +272,7 @@ input.submit
 button:focus,
 button:focus,
 input.submit:focus
 input.submit:focus
 {
 {
-	font-effect: blur(3px #fff);
+	font-effect: blur(3dp #fff);
 }
 }
 
 
 button:hover,
 button:hover,
@@ -294,16 +297,16 @@ input.submit:disabled
 input.text, input.password
 input.text, input.password
 {
 {
 	box-sizing: border-box;
 	box-sizing: border-box;
-	height: 31px;
-	padding: 10px 10px 0px;
+	height: 31dp;
+	padding: 10dp 10dp 0;
 	decorator: tiled-horizontal( text-l, text-c, auto ); /* Right becomes mirrored left */
 	decorator: tiled-horizontal( text-l, text-c, auto ); /* Right becomes mirrored left */
 	cursor: text;
 	cursor: text;
 }
 }
 
 
 textarea
 textarea
 {
 {
-	padding: 14px 12px 10px;
-	decorator: ninepatch( textarea, textarea-inner );
+	padding: 14dp 12dp 10dp;
+	decorator: ninepatch( textarea, textarea-inner, 1.0 );
 	cursor: text;
 	cursor: text;
 }
 }
 
 
@@ -314,22 +317,22 @@ dataselect,
 textarea
 textarea
 {
 {
 	color: #333;
 	color: #333;
-	font-size: 13px;
+	font-size: 13dp;
 }
 }
 
 
 datagrid input.text, table input.text
 datagrid input.text, table input.text
 {
 {
 	box-sizing: border-box;
 	box-sizing: border-box;
 	width: 100%;
 	width: 100%;
-	height: 18px;
+	height: 18dp;
 	margin: 0;
 	margin: 0;
-	padding: 0 5px;
+	padding: 0 5dp;
 
 
-	border-width: 1px;
+	border-width: 1dp;
 	border-color: black;
 	border-color: black;
 	background-color: white;
 	background-color: white;
 
 
-	font-size: 15px;
+	font-size: 15dp;
 	
 	
 	decorator: none;
 	decorator: none;
 }
 }
@@ -339,18 +342,18 @@ datagrid input.text, table input.text
 select,
 select,
 dataselect
 dataselect
 {
 {
-	width: 175px;
-	height: 37px;
+	width: 175dp;
+	height: 37dp;
 }
 }
 
 
 select selectvalue,
 select selectvalue,
 dataselect selectvalue
 dataselect selectvalue
 {
 {
 	width: auto;
 	width: auto;
-	margin-right: 30px;
+	margin-right: 30dp;
 	
 	
-	height: 26px;
-	padding: 11px 10px 0px 10px;
+	height: 26dp;
+	padding: 11dp 10dp 0dp 10dp;
 
 
 	decorator: image( selectvalue  );
 	decorator: image( selectvalue  );
 }
 }
@@ -358,8 +361,8 @@ dataselect selectvalue
 select selectarrow,
 select selectarrow,
 dataselect selectarrow
 dataselect selectarrow
 {
 {
-	width: 30px;
-	height: 37px;
+	width: 30dp;
+	height: 37dp;
 	
 	
 	decorator: image( selectarrow );
 	decorator: image( selectarrow );
 }
 }
@@ -381,11 +384,11 @@ dataselect selectarrow:checked
 select selectbox,
 select selectbox,
 dataselect selectbox
 dataselect selectbox
 {
 {
-	margin-left: 1px;
-	margin-top: -7px;
-	margin-bottom: -10px;
-	width: 162px;
-	padding: 1px 4px 4px 4px;
+	margin-left: 1dp;
+	margin-top: -7dp;
+	margin-bottom: -10dp;
+	width: 162dp;
+	padding: 1dp 4dp 4dp 4dp;
 }
 }
 
 
 select selectbox,
 select selectbox,
@@ -404,7 +407,7 @@ select selectbox option,
 dataselect selectbox option
 dataselect selectbox option
 {
 {
 	width: auto;
 	width: auto;
-	padding: 3px 0 3px 6px;
+	padding: 3dp 0 3dp 6dp;
 	background: #DDDD;
 	background: #DDDD;
 }
 }
 
 
@@ -431,10 +434,10 @@ dataselect selectbox option:hover
 input.radio,
 input.radio,
 input.checkbox
 input.checkbox
 {
 {
-	width: 30px;
-	height: 30px;
+	width: 30dp;
+	height: 30dp;
 
 
-	vertical-align: -11px;
+	vertical-align: -11dp;
 }
 }
 
 
 input.radio
 input.radio
@@ -498,22 +501,22 @@ input.checkbox:checked:active
 }
 }
 
 
 input.range {
 input.range {
-	width: 200px;
-	height: 32px;
-	vertical-align: -12px;
+	width: 200dp;
+	height: 32dp;
+	vertical-align: -12dp;
 }
 }
 input.range slidertrack {
 input.range slidertrack {
-	margin-top: 3px;
-	height: 22px;
+	margin-top: 3dp;
+	height: 22dp;
 	image-color: #ecc;
 	image-color: #ecc;
-	decorator: ninepatch( range-track, range-track-inner );
+	decorator: ninepatch( range-track, range-track-inner, 1.0 );
 }
 }
 input.range sliderbar {
 input.range sliderbar {
-	margin-left: -8px;
-	margin-right: -7px;
-	margin-top: -3px;
-	width: 34px;
-	height: 23px;
+	margin-left: -8dp;
+	margin-right: -7dp;
+	margin-top: -3dp;
+	width: 34dp;
+	height: 23dp;
 	decorator: image( range-bar );
 	decorator: image( range-bar );
 }
 }
 input.range:hover sliderbar {
 input.range:hover sliderbar {
@@ -523,9 +526,9 @@ input.range sliderbar:active {
 	image-color: #c80;
 	image-color: #c80;
 }
 }
 input.range sliderarrowdec, input.range sliderarrowinc {
 input.range sliderarrowdec, input.range sliderarrowinc {
-	width: 17px;
-	height: 17px;
-	margin-top: 6px;
+	width: 17dp;
+	height: 17dp;
+	margin-top: 6dp;
 }
 }
 input.range sliderarrowdec        { decorator: image( range-dec        ); }
 input.range sliderarrowdec        { decorator: image( range-dec        ); }
 input.range sliderarrowinc        { decorator: image( range-inc        ); }
 input.range sliderarrowinc        { decorator: image( range-inc        ); }
@@ -535,32 +538,32 @@ input.range sliderarrowdec:active { decorator: image( range-dec-active ); }
 input.range sliderarrowinc:active { decorator: image( range-inc-active ); }
 input.range sliderarrowinc:active { decorator: image( range-inc-active ); }
 
 
 thead tr {
 thead tr {
-	height: 35px;
+	height: 35dp;
 	decorator: tiled-horizontal( datagridheader-l, datagridheader-c, datagridheader-r );
 	decorator: tiled-horizontal( datagridheader-l, datagridheader-c, datagridheader-r );
 }
 }
 thead td {
 thead td {
-	padding-top: 11px;
+	padding-top: 11dp;
 }
 }
 
 
 tbody {
 tbody {
 	/* Margin left/right only affects the background positioning for the decorator, not the cell placement */
 	/* Margin left/right only affects the background positioning for the decorator, not the cell placement */
-	margin-left: 5px;
-	margin-right: 4px;
+	margin-left: 5dp;
+	margin-right: 4dp;
 	/* Padding top/bottom adds extra spacing between the header row and the body, and between the body and table bottom */
 	/* Padding top/bottom adds extra spacing between the header row and the body, and between the body and table bottom */
-	padding-top: 4px;
-	padding-bottom: 4px;
+	padding-top: 4dp;
+	padding-bottom: 4dp;
 }
 }
 tbody tr {
 tbody tr {
-	margin-left: 9px;
-	margin-right: 8px;
+	margin-left: 9dp;
+	margin-right: 8dp;
 	color: black;
 	color: black;
 }
 }
 
 
 datagrid datagridheader
 datagrid datagridheader
 {
 {
 	width: auto;
 	width: auto;
-	height: 25px;
-	padding: 5px 10px 0px 10px;
+	height: 25dp;
+	padding: 5dp 10dp 0 10dp;
 
 
 	decorator: tiled-horizontal( datagridheader-l, datagridheader-c, datagridheader-r );
 	decorator: tiled-horizontal( datagridheader-l, datagridheader-c, datagridheader-r );
 }
 }
@@ -569,9 +572,9 @@ datagrid datagridbody
 {
 {
 	color: black;
 	color: black;
 
 
-	margin-left: 4px;
-	margin-right: 3px;
-	padding: 0px 4px 4px 4px;
+	margin-left: 4dp;
+	margin-right: 3dp;
+	padding: 0 4dp 4dp 4dp;
 }
 }
 
 
 
 
@@ -580,9 +583,9 @@ datagridexpand, expand
 {
 {
 	display: block;
 	display: block;
 	
 	
-	margin: 1px 0px 1px 5px;
-	height: 17px;
-	width: 17px;
+	margin: 1dp 0 1dp 5dp;
+	height: 17dp;
+	width: 17dp;
 	
 	
 	decorator: image( datagridexpand );
 	decorator: image( datagridexpand );
 }
 }
@@ -615,10 +618,10 @@ datagridexpand.collapsed:active, expand.collapsed:active
 
 
 scrollbarvertical
 scrollbarvertical
 {
 {
-	margin-top: -6px;
-	margin-bottom: -6px;
-	margin-right: -11px;
-	width: 27px;
+	margin-top: -6dp;
+	margin-bottom: -6dp;
+	margin-right: -11dp;
+	width: 27dp;
 }
 }
 
 
 scrollbarvertical slidertrack
 scrollbarvertical slidertrack
@@ -632,9 +635,9 @@ scrollbarvertical slidertrack:active
 
 
 scrollbarvertical sliderbar
 scrollbarvertical sliderbar
 {
 {
-	margin-left: 4px;
-	width: 23px;
-	min-height: 46px;
+	margin-left: 4dp;
+	width: 23dp;
+	min-height: 46dp;
 
 
 	decorator: tiled-vertical( sliderbar-t, sliderbar-c, sliderbar-b );
 	decorator: tiled-vertical( sliderbar-t, sliderbar-c, sliderbar-b );
 }
 }
@@ -650,8 +653,8 @@ scrollbarvertical sliderbar:active
 scrollbarvertical sliderarrowdec,
 scrollbarvertical sliderarrowdec,
 scrollbarvertical sliderarrowinc
 scrollbarvertical sliderarrowinc
 {
 {
-	width: 27px;
-	height: 24px;
+	width: 27dp;
+	height: 24dp;
 }
 }
 scrollbarvertical sliderarrowdec
 scrollbarvertical sliderarrowdec
 {
 {
@@ -681,15 +684,15 @@ scrollbarvertical sliderarrowinc:active
 
 
 scrollbarhorizontal
 scrollbarhorizontal
 {
 {
-	width: 0px;
-	height: 0px;
+	width: 0;
+	height: 0;
 }
 }
 
 
 textarea scrollbarvertical
 textarea scrollbarvertical
 {
 {
 	cursor: arrow;
 	cursor: arrow;
-	margin: 10px 0px 4px 0;
-	width: 12px;
+	margin: 10dp 0 4dp 0;
+	width: 12dp;
 }
 }
 textarea scrollbarvertical slidertrack 
 textarea scrollbarvertical slidertrack 
 { 
 { 
@@ -697,28 +700,28 @@ textarea scrollbarvertical slidertrack
 }
 }
 textarea scrollbarvertical sliderbar
 textarea scrollbarvertical sliderbar
 {
 {
-	margin-left: 2px;
-	width: 10px;
-	min-height: 16px;
+	margin-left: 2dp;
+	width: 10dp;
+	min-height: 16dp;
 }
 }
 textarea scrollbarvertical sliderarrowdec,
 textarea scrollbarvertical sliderarrowdec,
 textarea scrollbarvertical sliderarrowinc
 textarea scrollbarvertical sliderarrowinc
 {
 {
-	width: 0px;
-	height: 0px;
+	width: 0;
+	height: 0;
 }
 }
 
 
 textarea scrollbarhorizontal
 textarea scrollbarhorizontal
 {
 {
 	cursor: arrow;
 	cursor: arrow;
-	margin-left: 7px;
-	height: 12px;
+	margin-left: 7dp;
+	height: 12dp;
 }
 }
 textarea scrollbarhorizontal sliderbar
 textarea scrollbarhorizontal sliderbar
 {
 {
 	background-color: #BC0000CC;
 	background-color: #BC0000CC;
-	height: 8px;
-	min-width: 10px;
+	height: 8dp;
+	min-width: 10dp;
 }
 }
 textarea scrollbarhorizontal sliderbar:hover
 textarea scrollbarhorizontal sliderbar:hover
 {
 {

+ 1 - 1
Samples/assets/window.rml

@@ -14,6 +14,6 @@
 		<div id="content">
 		<div id="content">
 		</div>
 		</div>
 	</div>
 	</div>
-	<handle size_target="#document" style="position: absolute; width: 16px; height: 16px; bottom: 0px; right: 0px; cursor: resize;"></handle>
+	<handle size_target="#document" style="position: absolute; width: 16dp; height: 16dp; bottom: 0px; right: 0px; cursor: resize;"></handle>
 </body>
 </body>
 </template>
 </template>

+ 30 - 28
Samples/basic/animation/data/animation.rml

@@ -5,11 +5,13 @@
 	<style>
 	<style>
 		body.window
 		body.window
 		{
 		{
-			max-width: 2000px;
-			max-height: 2000px;
-			width: 1600px;
-			height: 750px;
-			perspective: 3000px;
+			max-width: 2000dp;
+			max-height: 2000dp;
+			left: 80dp;
+			right: 80dp;
+			top: 50dp;
+			bottom: 50dp;
+			perspective: 3000dp;
 			/*opacity: 0;*/
 			/*opacity: 0;*/
 		}
 		}
 		section
 		section
@@ -25,7 +27,7 @@
 			text-align: left;
 			text-align: left;
 		}
 		}
 		button {
 		button {
-			margin-top: 50px;
+			margin-top: 50dp;
 		}
 		}
 		div#title_bar div#icon
 		div#title_bar div#icon
 		{
 		{
@@ -35,13 +37,13 @@
 		spacer
 		spacer
 		{
 		{
 			display: inline-block;
 			display: inline-block;
-			width: 25px;
+			width: 25dp;
 		}
 		}
 		
 		
 		#start_game 
 		#start_game 
 		{
 		{
 			opacity: 0.8;
 			opacity: 0.8;
-			transform: rotate(370deg) translateX(100px) scale(1.2);
+			transform: rotate(370deg) translateX(100dp) scale(1.2);
 			transform-origin: 30% 80% 0;
 			transform-origin: 30% 80% 0;
 		}
 		}
 		#options {
 		#options {
@@ -58,7 +60,7 @@
 			to { transform: scale(1.0) rotate(360deg); }
 			to { transform: scale(1.0) rotate(360deg); }
 		}
 		}
 		#high_scores {
 		#high_scores {
-			margin-left: -100px;
+			margin-left: -100dp;
 		}
 		}
 		
 		
 		@keyframes fadeout {
 		@keyframes fadeout {
@@ -104,18 +106,18 @@
 		
 		
 		div.container
 		div.container
 		{
 		{
-			margin-top: 15px;
+			margin-top: 15dp;
 			width: 100%;
 			width: 100%;
-			height: 200px;
+			height: 200dp;
 			background-color: #ae8484aa;
 			background-color: #ae8484aa;
 		}
 		}
 		div.plain
 		div.plain
 		{
 		{
 			font-size: 1.2em;
 			font-size: 1.2em;
-			padding: 10px;
+			padding: 10dp;
 			margin: auto;
 			margin: auto;
-			width: 130px;
-			height: 70px;
+			width: 130dp;
+			height: 70dp;
 			background-color: #c66;
 			background-color: #c66;
 		}
 		}
 		div.plain:hover { background-color: #ddb700; }
 		div.plain:hover { background-color: #ddb700; }
@@ -126,7 +128,7 @@
 			/* Note the translateX vs translateY in animation target, and rotateZ vs rotate3d, scaleX vs scaleY.
 			/* Note the translateX vs translateY in animation target, and rotateZ vs rotate3d, scaleX vs scaleY.
 			   In order to match, they are converted to their generic forms, translate3d, rotate3d, and scale3d.
 			   In order to match, they are converted to their generic forms, translate3d, rotate3d, and scale3d.
 			   For rotate3d to match another rotation, their rotation axes must align. */
 			   For rotate3d to match another rotation, their rotation axes must align. */
-			transform: translateX(100px) rotateZ(70deg) scaleX(1.3);
+			transform: translateX(100dp) rotateZ(70deg) scaleX(1.3);
 		}
 		}
 		#combine {
 		#combine {
 			transform: rotate(45deg);
 			transform: rotate(45deg);
@@ -134,13 +136,13 @@
 		#decomposition {
 		#decomposition {
 			/* To interpolate the rotate3d transforms, we need to decompose the matrix, 
 			/* To interpolate the rotate3d transforms, we need to decompose the matrix, 
 			   see the element info in the debugger for the resulting matrix. */
 			   see the element info in the debugger for the resulting matrix. */
-			transform: translateX(100px) rotate3d(1.0, 0, 1.0, 0deg);
+			transform: translateX(100dp) rotate3d(1.0, 0, 1.0, 0deg);
 		}
 		}
 		
 		
 		/* -- MIXED UNITS TESTS */
 		/* -- MIXED UNITS TESTS */
 		#abs_rel {
 		#abs_rel {
 			margin: 0;
 			margin: 0;
-			margin-left: 50px;
+			margin-left: 50dp;
 		}
 		}
 		#abs_rel_transform {
 		#abs_rel_transform {
 			margin: 0;
 			margin: 0;
@@ -149,7 +151,7 @@
 		#animation_event {
 		#animation_event {
 			position: relative;
 			position: relative;
 			margin: 0;
 			margin: 0;
-			top: 50px; left: 50px;
+			top: 50dp; left: 50dp;
 		}
 		}
 		/* -- TRANSITION TESTS */
 		/* -- TRANSITION TESTS */
 		#transition_test {
 		#transition_test {
@@ -157,16 +159,16 @@
 		}
 		}
 		#transition_test:hover {
 		#transition_test:hover {
 			/*transition: padding-left background-color transform 0.8s quadratic-out 1.0;*/
 			/*transition: padding-left background-color transform 0.8s quadratic-out 1.0;*/
-			padding-left: 60px;
+			padding-left: 60dp;
 			transform: scale(1.5);
 			transform: scale(1.5);
 		} 
 		} 
 		#transition_class {
 		#transition_class {
-			margin-left: 50px;
+			margin-left: 50dp;
 			transition: all 0.5s cubic-out;
 			transition: all 0.5s cubic-out;
 			cursor: pointer;
 			cursor: pointer;
 		}
 		}
 		#transition_class.move_me {
 		#transition_class.move_me {
-			margin-left: -50px;
+			margin-left: -50dp;
 			background-color: #dd3;
 			background-color: #dd3;
 		}
 		}
 		
 		
@@ -177,10 +179,10 @@
 				transform: rotate(180deg);
 				transform: rotate(180deg);
 			}
 			}
 			40% {
 			40% {
-				transform: rotate(180deg) translateX(200px);
+				transform: rotate(180deg) translateX(200dp);
 			}
 			}
 			60% {
 			60% {
-				transform: rotate(180deg) translateX(-200px);
+				transform: rotate(180deg) translateX(-200dp);
 			}
 			}
 			75% {
 			75% {
 				transform: rotate(180deg);
 				transform: rotate(180deg);
@@ -213,15 +215,15 @@
 			position: relative;
 			position: relative;
 			margin: 0; padding: 0;
 			margin: 0; padding: 0;
 			top: 0; left: 0;
 			top: 0; left: 0;
-			width: 25px; height: 25px;
+			width: 25dp; height: 25dp;
 			animation: 2s cubic-in-out infinite alternate some-missing-keys;
 			animation: 2s cubic-in-out infinite alternate some-missing-keys;
 		}
 		}
 		#keyevent_response
 		#keyevent_response
 		{
 		{
 			position: relative;
 			position: relative;
 			margin: 0; padding: 0;
 			margin: 0; padding: 0;
-			top: 110px; left: 0;
-			width: 100px; height: 55px;
+			top: 110dp; left: 0;
+			height: 55dp;
 		}
 		}
 		#performance 
 		#performance 
 		{
 		{
@@ -229,7 +231,7 @@
 			bottom: 0; 
 			bottom: 0; 
 			height: 30%; 
 			height: 30%; 
 			width: 20%;
 			width: 20%;
-			left: -100px;
+			left: -100dp;
 			transform: scale(0.5) rotate(-90deg);
 			transform: scale(0.5) rotate(-90deg);
 		}
 		}
 	</style>
 	</style>
@@ -258,7 +260,7 @@
 	<h1>Mixed units tests</h1>
 	<h1>Mixed units tests</h1>
 	<div class="container"><div class="plain" id="abs_rel">Pixel vs percentage.</div></div>
 	<div class="container"><div class="plain" id="abs_rel">Pixel vs percentage.</div></div>
 	<div class="container"><div class="plain" id="abs_rel_transform">Pixel vs percentage transform.</div></div>
 	<div class="container"><div class="plain" id="abs_rel_transform">Pixel vs percentage transform.</div></div>
-	<div class="container"><div class="plain" id="animation_event">Animation event</div><div class="plain" id="keyevent_response">Events (press arrow keys)</div></div>
+	<div class="container"><div class="plain" id="animation_event">Animation event</div><div class="plain" id="keyevent_response">Events<br/><span style="font-size: 0.8em">(press arrow keys)</span></div></div>
 </section>
 </section>
 
 
 <section style="left: 75%;" id="transition_tests">
 <section style="left: 75%;" id="transition_tests">

+ 9 - 14
Samples/basic/animation/src/main.cpp

@@ -39,18 +39,13 @@
 class DemoWindow
 class DemoWindow
 {
 {
 public:
 public:
-	DemoWindow(const Rml::String &title, const Rml::Vector2f &position, Rml::Context *context)
+	DemoWindow(const Rml::String &title, Rml::Context *context)
 	{
 	{
 		using namespace Rml;
 		using namespace Rml;
 		document = context->LoadDocument("basic/animation/data/animation.rml");
 		document = context->LoadDocument("basic/animation/data/animation.rml");
 		if (document != nullptr)
 		if (document != nullptr)
 		{
 		{
-			{
-				document->GetElementById("title")->SetInnerRML(title);
-				document->SetProperty(PropertyId::Left, Property(position.x, Property::PX));
-				document->SetProperty(PropertyId::Top, Property(position.y, Property::PX));
-				//document->Animate("opacity", Property(0.0f, Property::NUMBER), 2.0f, Tween{ Tween::Quadratic, Tween::InOut }, -1, true, 1.0f);
-			}
+			document->GetElementById("title")->SetInnerRML(title);
 
 
 			// Button fun
 			// Button fun
 			{
 			{
@@ -260,17 +255,17 @@ public:
 			else if (key_identifier == Rml::Input::KI_LEFT)
 			else if (key_identifier == Rml::Input::KI_LEFT)
 			{
 			{
 				auto el = context->GetRootElement()->GetElementById("keyevent_response");
 				auto el = context->GetRootElement()->GetElementById("keyevent_response");
-				if (el) el->Animate("left", Property{ -200.f, Property::PX }, 0.5, Tween{ Tween::Cubic });
+				if (el) el->Animate("left", Property{ -200.f, Property::DP }, 0.5, Tween{ Tween::Cubic });
 			}
 			}
 			else if (key_identifier == Rml::Input::KI_RIGHT)
 			else if (key_identifier == Rml::Input::KI_RIGHT)
 			{
 			{
 				auto el = context->GetRootElement()->GetElementById("keyevent_response");
 				auto el = context->GetRootElement()->GetElementById("keyevent_response");
-				if (el) el->Animate("left", Property{ 200.f, Property::PX }, 0.5, Tween{ Tween::Cubic });
+				if (el) el->Animate("left", Property{ 200.f, Property::DP }, 0.5, Tween{ Tween::Cubic });
 			}
 			}
 			else if (key_identifier == Rml::Input::KI_UP)
 			else if (key_identifier == Rml::Input::KI_UP)
 			{
 			{
 				auto el = context->GetRootElement()->GetElementById("keyevent_response");
 				auto el = context->GetRootElement()->GetElementById("keyevent_response");
-				auto offset_right = Property{ 200.f, Property::PX };
+				auto offset_right = Property{ 200.f, Property::DP };
 				if (el) el->Animate("left", Property{ 0.f, Property::PX }, 0.5, Tween{ Tween::Cubic }, 1, true, 0, &offset_right);
 				if (el) el->Animate("left", Property{ 0.f, Property::PX }, 0.5, Tween{ Tween::Cubic }, 1, true, 0, &offset_right);
 			}
 			}
 			else if (key_identifier == Rml::Input::KI_DOWN)
 			else if (key_identifier == Rml::Input::KI_DOWN)
@@ -343,8 +338,8 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	RMLUI_UNUSED(argv);
 	RMLUI_UNUSED(argv);
 #endif
 #endif
 
 
-	const int width = 1800;
-	const int height = 1000;
+	const int width = 1700;
+	const int height = 900;
 
 
 
 
 	ShellRenderInterfaceOpenGL opengl_renderer;
 	ShellRenderInterfaceOpenGL opengl_renderer;
@@ -378,14 +373,14 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	EventInstancer event_listener_instancer;
 	EventInstancer event_listener_instancer;
 	Rml::Factory::RegisterEventListenerInstancer(&event_listener_instancer);
 	Rml::Factory::RegisterEventListenerInstancer(&event_listener_instancer);
 
 
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 
-	window = new DemoWindow("Animation sample", Rml::Vector2f(81, 100), context);
+	window = new DemoWindow("Animation sample", context);
 	window->GetDocument()->AddEventListener(Rml::EventId::Keydown, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Keydown, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Keyup, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Keyup, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Animationend, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Animationend, new Event("hello"));

+ 10 - 9
Samples/basic/benchmark/data/benchmark.rml

@@ -5,24 +5,25 @@
 	<style>
 	<style>
 		body.window
 		body.window
 		{
 		{
-			max-width: 2000px;
-			max-height: 2000px;
-			width: 1600px;
-			height: 750px;
+			left: 80dp;
+			right: 80dp;
+			top: 50dp;
+			bottom: 50dp;
+			max-width: 2000dp;
+			max-height: 2000dp;
 		}
 		}
 		#fps 
 		#fps 
 		{
 		{
 			position: absolute;
 			position: absolute;
-			top: 55px;
-			left: 20px;
+			top: 55dp;
+			left: 20dp;
 			font-size: 0.85em;
 			font-size: 0.85em;
 			text-align: left;
 			text-align: left;
 		}
 		}
 		#performance 
 		#performance 
 		{
 		{
-			width: 800px;
-			height: 300px;
-			/*transform: scale(0.6) rotate(-60deg);*/
+			width: 800dp;
+			height: 300dp;
 		}
 		}
 	</style>
 	</style>
 </head>
 </head>

+ 3 - 5
Samples/basic/benchmark/src/main.cpp

@@ -36,7 +36,7 @@
 class DemoWindow
 class DemoWindow
 {
 {
 public:
 public:
-	DemoWindow(const Rml::String &title, const Rml::Vector2f &position, Rml::Context *context)
+	DemoWindow(const Rml::String &title, Rml::Context *context)
 	{
 	{
 		using namespace Rml;
 		using namespace Rml;
 		document = context->LoadDocument("basic/benchmark/data/benchmark.rml");
 		document = context->LoadDocument("basic/benchmark/data/benchmark.rml");
@@ -44,8 +44,6 @@ public:
 		{
 		{
 			{
 			{
 				document->GetElementById("title")->SetInnerRML(title);
 				document->GetElementById("title")->SetInnerRML(title);
-				document->SetProperty(PropertyId::Left, Property(position.x, Property::PX));
-				document->SetProperty(PropertyId::Top, Property(position.y, Property::PX));
 			}
 			}
 
 
 			document->Show();
 			document->Show();
@@ -289,14 +287,14 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	EventInstancer event_listener_instancer;
 	EventInstancer event_listener_instancer;
 	Rml::Factory::RegisterEventListenerInstancer(&event_listener_instancer);
 	Rml::Factory::RegisterEventListenerInstancer(&event_listener_instancer);
 
 
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 
-	window = new DemoWindow("Benchmark sample", Rml::Vector2f(81, 100), context);
+	window = new DemoWindow("Benchmark sample", context);
 	window->GetDocument()->AddEventListener(Rml::EventId::Keydown, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Keydown, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Keyup, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Keyup, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Animationend, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Animationend, new Event("hello"));

+ 1 - 1
Samples/basic/bitmapfont/src/main.cpp

@@ -115,7 +115,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
     // Load bitmap font
     // Load bitmap font
 	if (!Rml::LoadFontFace("basic/bitmapfont/data/Comfortaa_Regular_22.fnt"))
 	if (!Rml::LoadFontFace("basic/bitmapfont/data/Comfortaa_Regular_22.fnt"))

+ 1 - 1
Samples/basic/customlog/src/main.cpp

@@ -102,7 +102,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 

+ 27 - 25
Samples/basic/databinding/data/databinding.rml

@@ -5,10 +5,12 @@
 <style>
 <style>
 body.window
 body.window
 {
 {
-	width: 1300px;
-	height: 750px;
-	min-width: 1090px;
-	min-height: 300px;
+	left: 80dp;
+	right: 80dp;
+	top: 50dp;
+	bottom: 50dp;
+	min-width: 1040dp;
+	min-height: 300dp;
 	max-width: -1px;
 	max-width: -1px;
 	max-height: -1px;
 	max-height: -1px;
 }
 }
@@ -30,18 +32,18 @@ tabs
 	position: fixed;
 	position: fixed;
 	clip: none;
 	clip: none;
 	text-align: right;
 	text-align: right;
-	top: -47px;
-	left: 205px;
-	right: 10px;
+	top: -47dp;
+	left: 205dp;
+	right: 10dp;
 }
 }
 tab
 tab
 {
 {
 	display: inline-block;
 	display: inline-block;
-	width: 100px;
-	padding: 0px 20px;
-	line-height: 40px;
+	width: 100dp;
+	padding: 0 20dp;
+	line-height: 40dp;
 	
 	
-	font-size: 16px;
+	font-size: 16dp;
 	color: #ddd;
 	color: #ddd;
 	text-align: center;
 	text-align: center;
 	
 	
@@ -65,21 +67,21 @@ panels
 panel
 panel
 {
 {
 	display: block;
 	display: block;
-	padding: 30px;
+	padding: 30dp;
 	margin-left: auto;
 	margin-left: auto;
 	margin-right: auto;
 	margin-right: auto;
-	max-width: 500px;
+	max-width: 500dp;
 }
 }
 h1
 h1
 {
 {
 	margin: 1.4em 0 0.7em;
 	margin: 1.4em 0 0.7em;
-	font-size: 18px;
+	font-size: 18dp;
 }
 }
 p.title
 p.title
 {
 {
-	font-size: 35px;
+	font-size: 35dp;
 	color: #b33;
 	color: #b33;
-	font-effect: glow(2px #ed5);
+	font-effect: glow(2dp #ed5);
 }
 }
 .center {
 .center {
 	text-align: center;
 	text-align: center;
@@ -95,11 +97,11 @@ p.title
 	font-size: 1.8em;
 	font-size: 1.8em;
 }
 }
 .mouse_detector {
 .mouse_detector {
-	width: 300px;
+	width: 300dp;
 	min-height: 2em;
 	min-height: 2em;
-	line-height: 30px;
+	line-height: 30dp;
 	background-color: #909090;
 	background-color: #909090;
-	border: 1px #666;
+	border: 1dp #666;
 	margin: 2em auto;
 	margin: 2em auto;
 	cursor: pointer;
 	cursor: pointer;
 }
 }
@@ -122,14 +124,14 @@ input.text.two-wide {
 }
 }
 form h2 {
 form h2 {
 	display: block;
 	display: block;
-	font-size: 16px;
+	font-size: 16dp;
 	font-weight: bold;
 	font-weight: bold;
 	margin-top: 1em;
 	margin-top: 1em;
 	margin-bottom: 0.3em;
 	margin-bottom: 0.3em;
 }
 }
 #rating {
 #rating {
 	display: inline-block;
 	display: inline-block;
-	width: 40px;
+	width: 40dp;
 	padding-left: 1em;
 	padding-left: 1em;
 }
 }
 #rating_emoji { 
 #rating_emoji { 
@@ -138,8 +140,8 @@ form h2 {
 }
 }
 #controls textarea 
 #controls textarea 
 {
 {
-	font-size: 18px;
-	font-effect: outline(2px #060);
+	font-size: 18dp;
+	font-effect: outline(2dp #060);
 	color: #ddd;
 	color: #ddd;
 	caret-color: #060;
 	caret-color: #060;
 }
 }
@@ -178,7 +180,7 @@ li {
 	<p>Data binding demo. We rate this a good old {{rating}}!</p>
 	<p>Data binding demo. We rate this a good old {{rating}}!</p>
 	<input type="range" name="rating" min="0" max="100" step="1" value="50" data-value="rating"/>
 	<input type="range" name="rating" min="0" max="100" step="1" value="50" data-value="rating"/>
 	<div data-visible="rating > 50">Thanks for the <span data-if="rating < 80">good</span><span data-if="rating >= 80">awesome</span> rating!</div>
 	<div data-visible="rating > 50">Thanks for the <span data-if="rating < 80">good</span><span data-if="rating >= 80">awesome</span> rating!</div>
-	<div class="mouse_detector" style="height: 70px;"
+	<div class="mouse_detector" style="height: 70dp;"
 		data-event-mousemove="mouse_detector = 'x: ' + ev.mouse_x + '<br/>y: ' + ev.mouse_y"
 		data-event-mousemove="mouse_detector = 'x: ' + ev.mouse_x + '<br/>y: ' + ev.mouse_y"
 		data-event-click="add_mouse_pos(); hello_world = 'Hello click!'"
 		data-event-click="add_mouse_pos(); hello_world = 'Hello click!'"
 		data-rml="mouse_detector">
 		data-rml="mouse_detector">
@@ -268,7 +270,7 @@ li {
 		<div>
 		<div>
 			<textarea cols="25" rows="4" wrap="nowrap" name="message">😍 Hello 🌐 World! 😎</textarea>
 			<textarea cols="25" rows="4" wrap="nowrap" name="message">😍 Hello 🌐 World! 😎</textarea>
 		</div>
 		</div>
-		<div style="margin-bottom: 15px;">
+		<div style="margin-bottom: 15dp;">
 			<input type="submit">Submit</input>
 			<input type="submit">Submit</input>
 		</div>
 		</div>
 	</form>
 	</form>

+ 3 - 10
Samples/basic/databinding/src/main.cpp

@@ -312,16 +312,13 @@ namespace FormsExample {
 class DemoWindow : public Rml::EventListener
 class DemoWindow : public Rml::EventListener
 {
 {
 public:
 public:
-	DemoWindow(const Rml::String &title, const Rml::Vector2f &position, Rml::Context *context)
+	DemoWindow(const Rml::String &title, Rml::Context *context)
 	{
 	{
 		using namespace Rml;
 		using namespace Rml;
 		document = context->LoadDocument("basic/databinding/data/databinding.rml");
 		document = context->LoadDocument("basic/databinding/data/databinding.rml");
 		if (document)
 		if (document)
 		{
 		{
 			document->GetElementById("title")->SetInnerRML(title);
 			document->GetElementById("title")->SetInnerRML(title);
-			document->SetProperty(PropertyId::Left, Property(position.x, Property::PX));
-			document->SetProperty(PropertyId::Top, Property(position.y, Property::PX));
-
 			document->Show();
 			document->Show();
 		}
 		}
 	}
 	}
@@ -347,10 +344,6 @@ public:
 			{
 			{
 				Shell::RequestExit();
 				Shell::RequestExit();
 			}
 			}
-			else if (key_identifier == Rml::Input::KI_F8)
-			{
-				Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible());
-			}
 		}
 		}
 		break;
 		break;
 
 
@@ -446,11 +439,11 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 	
 	
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 
-	auto demo_window = Rml::MakeUnique<DemoWindow>("Data binding", Rml::Vector2f(150, 50), context);
+	auto demo_window = Rml::MakeUnique<DemoWindow>("Data binding", context);
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keydown, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keydown, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keyup, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keyup, demo_window.get());
 
 

+ 142 - 140
Samples/basic/demo/data/demo.rml

@@ -38,10 +38,12 @@
 
 
 body.window
 body.window
 {
 {
-	width: 1300px;
-	height: 750px;
-	min-width: 1040px;
-	min-height: 300px;
+	left: 80dp;
+	right: 80dp;
+	top: 50dp;
+	bottom: 50dp;
+	min-width: 1040dp;
+	min-height: 300dp;
 	max-width: -1px;
 	max-width: -1px;
 	max-height: -1px;
 	max-height: -1px;
 }
 }
@@ -64,18 +66,18 @@ tabs
 	position: fixed;
 	position: fixed;
 	clip: none;
 	clip: none;
 	text-align: right;
 	text-align: right;
-	top: -47px;
-	left: 205px;
-	right: 10px;
+	top: -47dp;
+	left: 205dp;
+	right: 10dp;
 }
 }
 tab
 tab
 {
 {
-    width: 90px;
-	padding: 0px 20px;
-	line-height: 40px;
+	width: 90dp;
+	padding: 0 20dp;
+	line-height: 40dp;
 	display: inline-block;
 	display: inline-block;
 	
 	
-	font-size: 15px;
+	font-size: 15dp;
 	color: #ddd;
 	color: #ddd;
 	text-align: center;
 	text-align: center;
 	
 	
@@ -99,10 +101,10 @@ panels
 panel
 panel
 {
 {
     display: block;
     display: block;
-	padding: 30px;
+	padding: 30dp;
 	margin-left: auto;
 	margin-left: auto;
 	margin-right: auto;
 	margin-right: auto;
-	max-width: 500px;
+	max-width: 500dp;
 }
 }
 panel#welcome
 panel#welcome
 {
 {
@@ -111,13 +113,13 @@ panel#welcome
 h1
 h1
 {
 {
 	margin: 1.4em 0 0.7em;
 	margin: 1.4em 0 0.7em;
-	font-size: 18px;
+	font-size: 18dp;
 }
 }
 p.title
 p.title
 {
 {
-	font-size: 35px;
+	font-size: 35dp;
 	color: #b33;
 	color: #b33;
-	font-effect: glow(2px #ed5);
+	font-effect: glow(2dp #ed5);
 }
 }
 .center {
 .center {
 	text-align: center;
 	text-align: center;
@@ -139,9 +141,9 @@ p.title
 #decorators button.gradient
 #decorators button.gradient
 {
 {
 	decorator: gradient( vertical #415857 #5990A3 );
 	decorator: gradient( vertical #415857 #5990A3 );
-	border: 3px #415857;
-	border-radius: 8px;
-	margin-right: 12px;
+	border: 3dp #415857;
+	border-radius: 8dp;
+	margin-right: 12dp;
 }
 }
 #decorators button.gradient.horizontal
 #decorators button.gradient.horizontal
 {
 {
@@ -155,26 +157,26 @@ p.title
 
 
 #decorators .image-alien
 #decorators .image-alien
 {
 {
-	width: 64px;
-	height: 64px;
+	width: 64dp;
+	height: 64dp;
 	decorator: image( /assets/high_scores_alien_1.tga );
 	decorator: image( /assets/high_scores_alien_1.tga );
 }
 }
 #decorators .image-invader
 #decorators .image-invader
 {
 {
-	width: 51px;
-	height: 39px;
+	width: 51dp;
+	height: 39dp;
 	decorator: image( icon-invader );
 	decorator: image( icon-invader );
 }
 }
 .side-by-side
 .side-by-side
 {
 {
 	display: inline-block;
 	display: inline-block;
-	width: 120px;
+	width: 120dp;
 	vertical-align: middle;
 	vertical-align: middle;
 	text-align: center;
 	text-align: center;
 }
 }
 .tiled-box
 .tiled-box
 {
 {
-	height: 200px;
+	height: 200dp;
 	decorator: tiled-box(
 	decorator: tiled-box(
 		window-tl, window-t, window-tr, 
 		window-tl, window-t, window-tr, 
 		window-l, window-c, window-r,
 		window-l, window-c, window-r,
@@ -184,32 +186,32 @@ p.title
 .image-mode
 .image-mode
 {
 {
 	text-align: center;
 	text-align: center;
-	margin-top: 30px;
+	margin-top: 30dp;
 }
 }
 .image-mode > div
 .image-mode > div
 {
 {
 	display: inline-block;
 	display: inline-block;
-	width: 120px;
-	height: 50px;
-	padding: 5px 10px;
-	margin: 10px 10px;
+	width: 120dp;
+	height: 50dp;
+	padding: 5dp 10dp;
+	margin: 10dp 10dp;
 	background-color: #c662;
 	background-color: #c662;
-	border: 1px #777;
-	font-effect: shadow( 1px 1px #333 );
+	border: 1dp #777;
+	font-effect: shadow( 1dp 1dp #333 );
 }
 }
 #decorators .image-mode > div > p
 #decorators .image-mode > div > p
 {
 {
 	margin: -2em 0 0 0;
 	margin: -2em 0 0 0;
 	text-align: center;
 	text-align: center;
 }
 }
-.image-mode.small { margin-top: -20px; }
+.image-mode.small { margin-top: -20dp; }
 .image-mode.small > div
 .image-mode.small > div
 {
 {
-	width: 40px;
-	height: 20px;
+	width: 40dp;
+	height: 20dp;
 	padding: 0;
 	padding: 0;
-	margin-left: 60px;
-	margin-right: 60px;
+	margin-left: 60dp;
+	margin-right: 60dp;
 }
 }
 .align-default     { decorator: image( icon-invader scale-none             ); }
 .align-default     { decorator: image( icon-invader scale-none             ); }
 .align-right       { decorator: image( icon-invader scale-none right       ); }
 .align-right       { decorator: image( icon-invader scale-none right       ); }
@@ -231,60 +233,60 @@ p.title
 #font_effects div 
 #font_effects div 
 {
 {
 	display: inline-block;
 	display: inline-block;
-	width: 150px;
-	margin: 0px 30px 30px;
+	width: 150dp;
+	margin: 0 30dp 30dp;
 	text-align: center;
 	text-align: center;
-	font-size: 35px;
+	font-size: 35dp;
 	color: #b33;
 	color: #b33;
 }
 }
 #font_effects h1 
 #font_effects h1 
 {
 {
-	margin: 15px 0 10px 0;
+	margin: 15dp 0 10dp 0;
 }
 }
 #font_effects .glow
 #font_effects .glow
 {
 {
-	font-effect: glow(3px #ed5);
+	font-effect: glow(3dp #ed5);
 }
 }
 #font_effects .glow_sharper
 #font_effects .glow_sharper
 {
 {
-	font-effect: glow(3px 1px #ed5);
+	font-effect: glow(3dp 1dp #ed5);
 }
 }
 #font_effects .glow_blurry
 #font_effects .glow_blurry
 {
 {
-	font-effect: glow(2px 7px #ed5);
+	font-effect: glow(2dp 7dp #ed5);
 }
 }
 #font_effects .glow_shadow
 #font_effects .glow_shadow
 {
 {
 	color: #ed5;
 	color: #ed5;
-	font-effect: glow(2px 4px 2px 3px #644);
+	font-effect: glow(2dp 4dp 2dp 3dp #644);
 }
 }
 #font_effects .outline_small
 #font_effects .outline_small
 {
 {
-	font-effect: outline(2px #ed5);
+	font-effect: outline(2dp #ed5);
 }
 }
 #font_effects .outline_big
 #font_effects .outline_big
 {
 {
-	font-effect: outline(4px #ed5);
+	font-effect: outline(4dp #ed5);
 }
 }
 #font_effects .blur_small
 #font_effects .blur_small
 {
 {
 	color: transparent;
 	color: transparent;
-	font-effect: blur(3px #ed5);
+	font-effect: blur(3dp #ed5);
 }
 }
 #font_effects .blur_big
 #font_effects .blur_big
 {
 {
 	color: transparent;
 	color: transparent;
-	font-effect: blur(10px #ed5);
+	font-effect: blur(10dp #ed5);
 }
 }
 #font_effects .shadow_up
 #font_effects .shadow_up
 {
 {
 	font-weight: bold;
 	font-weight: bold;
-	font-effect: shadow(3px -3px #ed5);
+	font-effect: shadow(3dp -3dp #ed5);
 }
 }
 #font_effects .shadow_down
 #font_effects .shadow_down
 {
 {
 	font-weight: bold;
 	font-weight: bold;
-	font-effect: shadow(0px 2px #333);
+	font-effect: shadow(0px 2dp #333);
 }
 }
 
 
 
 
@@ -293,10 +295,10 @@ p.title
 #tweening_area
 #tweening_area
 {
 {
 	position: relative;
 	position: relative;
-	margin: 30px auto;
-	width: 400px;
-	height: 250px;
-	border: 1px #777;
+	margin: 30dp auto;
+	width: 400dp;
+	height: 250dp;
+	border: 1dp #777;
 	background-color: #ccc2;
 	background-color: #ccc2;
 	cursor: cross;
 	cursor: cross;
 }
 }
@@ -304,15 +306,15 @@ p.title
 {
 {
 	position: absolute;
 	position: absolute;
 	cursor: pointer;
 	cursor: pointer;
-	transform: translate(190px, 100px);
+	transform: translate(190dp, 100dp);
 }
 }
 
 
 #transition
 #transition
 {
 {
-	margin: 20px auto 30px;
-	width: 400px;
-	height: 250px;
-	border: 1px #777;
+	margin: 20dp auto 30dp;
+	width: 400dp;
+	height: 250dp;
+	border: 1dp #777;
 	background-color: #ccc2;
 	background-color: #ccc2;
 	position: relative;
 	position: relative;
 	overflow: hidden;
 	overflow: hidden;
@@ -320,38 +322,38 @@ p.title
 #transition > img
 #transition > img
 {
 {
 	position: absolute;
 	position: absolute;
-	top: -50px;
+	top: -50dp;
 	left: 50%;
 	left: 50%;
-	margin-left: -32px;
+	margin-left: -32dp;
 	transition: top left 0.6s back-out, opacity 0.4s, image-color 0.4s 0.3s quadratic-out;
 	transition: top left 0.6s back-out, opacity 0.4s, image-color 0.4s 0.3s quadratic-out;
 	opacity: 0;
 	opacity: 0;
 	image-color: #fff;
 	image-color: #fff;
 }
 }
 #transition:hover > img
 #transition:hover > img
 {
 {
-	top: 50px;
+	top: 50dp;
 	opacity: 1;
 	opacity: 1;
 	image-color: #f61;
 	image-color: #f61;
 }
 }
-#transition:hover .alien1 { left: 30%; top: 75px; }
-#transition:hover .alien3 { left: 70%; top: 75px; }
+#transition:hover .alien1 { left: 30%; top: 75dp; }
+#transition:hover .alien3 { left: 70%; top: 75dp; }
 #transition .defender
 #transition .defender
 { 
 { 
 	transition: image-color 0.3s 0.0s quadratic-out;
 	transition: image-color 0.3s 0.0s quadratic-out;
 	position: absolute;
 	position: absolute;
-	left: -44px;
-	top: 150px; opacity: 1; 
+	left: -44dp;
+	top: 150dp; opacity: 1; 
 }
 }
 #transition:hover .defender { image-color: #acf;  }
 #transition:hover .defender { image-color: #acf;  }
 #transition .ray { 
 #transition .ray { 
 	transition: top 0.4s back-out, opacity 0.4s cubic-in;
 	transition: top 0.4s back-out, opacity 0.4s cubic-in;
 	position: absolute;
 	position: absolute;
-	top: -130px;
+	top: -130dp;
 	left: 50%;
 	left: 50%;
 	opacity: 0;
 	opacity: 0;
-	margin-left: -20px;
-	width: 40px;
-	height: 200px;
+	margin-left: -20dp;
+	width: 40dp;
+	height: 200dp;
 	decorator: gradient( vertical #daf0 #fef6 );
 	decorator: gradient( vertical #daf0 #fef6 );
 }
 }
 #transition:hover .ray
 #transition:hover .ray
@@ -366,10 +368,10 @@ p.title
 }
 }
 
 
 .cube_container {
 .cube_container {
-	width: 200px;
-	height: 200px;
-	margin: 20px auto;
-	perspective: 500px;
+	width: 200dp;
+	height: 200dp;
+	margin: 20dp auto;
+	perspective: 500dp;
 }
 }
 .cube {
 .cube {
 	width: 100%;
 	width: 100%;
@@ -378,20 +380,20 @@ p.title
 	animation: 3s cube-rotate infinite back-in-out;
 	animation: 3s cube-rotate infinite back-in-out;
 }
 }
 .face {
 .face {
-	left: 50px; top: 50px;
+	left: 50dp; top: 50dp;
 	display: block;
 	display: block;
 	position: absolute;
 	position: absolute;
-	width: 100px;
-	height: 100px;
-	line-height: 100px;
-	font-size: 60px;
+	width: 100dp;
+	height: 100dp;
+	line-height: 100dp;
+	font-size: 60dp;
 	color: white;
 	color: white;
 	text-align: center;
 	text-align: center;
 }
 }
 /* Define each face based on direction */
 /* Define each face based on direction */
 .face.front {
 .face.front {
 	background: rgba(0, 0, 0, 160);
 	background: rgba(0, 0, 0, 160);
-	transform: translateZ(50px);
+	transform: translateZ(50dp);
 }
 }
 .face.front:hover {
 .face.front:hover {
 	background: rgba(255, 255, 0, 120);
 	background: rgba(255, 255, 0, 120);
@@ -399,23 +401,23 @@ p.title
 .face.back {
 .face.back {
 	background: rgba(0, 255, 0, 255);
 	background: rgba(0, 255, 0, 255);
 	color: black;
 	color: black;
-	transform: rotateY(180deg) translateZ(50px);
+	transform: rotateY(180deg) translateZ(50dp);
 }
 }
 .face.right {
 .face.right {
 	background: rgba(196, 0, 0, 200);
 	background: rgba(196, 0, 0, 200);
-	transform: rotateY(90deg) translateZ(50px);
+	transform: rotateY(90deg) translateZ(50dp);
 }
 }
 .face.left {
 .face.left {
 	background: rgba(0, 0, 196, 200);
 	background: rgba(0, 0, 196, 200);
-	transform: rotateY(-90deg) translateZ(50px);
+	transform: rotateY(-90deg) translateZ(50dp);
 }
 }
 .face.top {
 .face.top {
 	background: rgba(196, 196, 0, 200);
 	background: rgba(196, 196, 0, 200);
-	transform: rotateX(90deg) translateZ(50px);
+	transform: rotateX(90deg) translateZ(50dp);
 }
 }
 .face.bottom {
 .face.bottom {
 	background: rgba(196, 0, 196, 200);
 	background: rgba(196, 0, 196, 200);
-	transform: rotateX(-90deg) translateZ(50px);
+	transform: rotateX(-90deg) translateZ(50dp);
 }
 }
 
 
 
 
@@ -436,14 +438,14 @@ input.text.two-wide {
 }
 }
 form h2 {
 form h2 {
 	display: block;
 	display: block;
-	font-size: 16px;
+	font-size: 16dp;
 	font-weight: bold;
 	font-weight: bold;
 	margin-top: 0.6em;
 	margin-top: 0.6em;
 	margin-bottom: 0.4em;
 	margin-bottom: 0.4em;
 }
 }
 #rating {
 #rating {
 	display: inline-block;
 	display: inline-block;
-	width: 40px;
+	width: 40dp;
 	padding-left: 1em;
 	padding-left: 1em;
 }
 }
 #rating_emoji { 
 #rating_emoji { 
@@ -451,56 +453,56 @@ form h2 {
 	font-size: 1.7em;
 	font-size: 1.7em;
 }
 }
 progressbar {
 progressbar {
-	margin: 10px 20px;
+	margin: 10dp 20dp;
 	display: inline-block;
 	display: inline-block;
 	vertical-align: middle;
 	vertical-align: middle;
 }
 }
 #gauge { 
 #gauge { 
 	decorator: image( gauge );
 	decorator: image( gauge );
-	width: 100px;
-	height: 86px;
+	width: 100dp;
+	height: 86dp;
 	fill-image: gauge-fill;
 	fill-image: gauge-fill;
 }
 }
 #progress_horizontal { 
 #progress_horizontal { 
 	decorator: tiled-horizontal( progress-l, progress-c, progress-r );
 	decorator: tiled-horizontal( progress-l, progress-c, progress-r );
-	width: 150px;
-	height: 34px;
+	width: 150dp;
+	height: 34dp;
 }
 }
 #progress_horizontal fill {
 #progress_horizontal fill {
 	decorator: tiled-horizontal( progress-fill-l, progress-fill-c, progress-fill-r );
 	decorator: tiled-horizontal( progress-fill-l, progress-fill-c, progress-fill-r );
-	margin: 0 7px;
-	padding-left: 14px;
+	margin: 0 7dp;
+	padding-left: 14dp;
 }
 }
 #progress_label {
 #progress_label {
-	font-size: 18px;
+	font-size: 18dp;
 	color: #ceb;
 	color: #ceb;
 	margin-left: 1em;
 	margin-left: 1em;
 	margin-bottom: 0;
 	margin-bottom: 0;
 }
 }
 #gauge_value, #progress_value {
 #gauge_value, #progress_value {
-	font-size: 16px;
+	font-size: 16dp;
 	color: #4ADB2D;
 	color: #4ADB2D;
 	text-align: right;
 	text-align: right;
-	width: 53px;
-	font-effect: outline( 2px #555 );
+	width: 53dp;
+	font-effect: outline( 2dp #555 );
 }
 }
 #gauge_value {
 #gauge_value {
-	margin: 34px 0 0 18px;
+	margin: 34dp 0 0 18dp;
 }
 }
 #progress_value { 
 #progress_value { 
-	margin-left: -20px;
+	margin-left: -20dp;
 	display: inline-block;
 	display: inline-block;
 }
 }
 
 
 
 
 #form_output 
 #form_output 
 {
 {
-	border: 1px #666;
+	border: 1dp #666;
 	font-size: 0.9em;
 	font-size: 0.9em;
 	background-color: #ddd;
 	background-color: #ddd;
-	min-height: 180px;
-	margin-top: 10px;
-	padding: 5px 8px;
+	min-height: 180dp;
+	margin-top: 10dp;
+	padding: 5dp 8dp;
 	color: #222;
 	color: #222;
 	white-space: pre-wrap;
 	white-space: pre-wrap;
 	overflow: hidden auto;
 	overflow: hidden auto;
@@ -508,8 +510,8 @@ progressbar {
 
 
 #controls textarea 
 #controls textarea 
 {
 {
-	font-size: 18px;
-	font-effect: outline(2px #060);
+	font-size: 18dp;
+	font-effect: outline(2dp #060);
 	color: #ddd;
 	color: #ddd;
 	caret-color: #060;
 	caret-color: #060;
 }
 }
@@ -525,15 +527,15 @@ progressbar {
 #sandbox
 #sandbox
 {
 {
 	position: absolute;
 	position: absolute;
-	top: 20px;
-	right: 30px;
-	bottom: 20px;
-	left: 30px;
+	top: 20dp;
+	right: 30dp;
+	bottom: 20dp;
+	left: 30dp;
 	padding: 0;
 	padding: 0;
 }
 }
 #sandbox textarea
 #sandbox textarea
 {
 {
-	font-size: 13px;
+	font-size: 13dp;
 	color: #222;
 	color: #222;
 	font-family: rmlui-debugger-font;
 	font-family: rmlui-debugger-font;
 	box-sizing: border-box;
 	box-sizing: border-box;
@@ -546,13 +548,13 @@ progressbar {
 	background-color: #fff;
 	background-color: #fff;
 	border: 1px #000;
 	border: 1px #000;
 	height: 55%;
 	height: 55%;
-	margin-top: 15px;
+	margin-top: 15dp;
 	color: #000;
 	color: #000;
 	text-align: left;
 	text-align: left;
 	position: relative;
 	position: relative;
 }
 }
-#sandbox_rml_source { margin-left: -5px; }
-#sandbox_rcss_source { margin-left: 5px; }
+#sandbox_rml_source { margin-left: -5dp; }
+#sandbox_rcss_source { margin-left: 5dp; }
 </style>
 </style>
 </head>
 </head>
 
 
@@ -592,16 +594,16 @@ progressbar {
 	<h1>Tiled-horizontal decorator</h1>
 	<h1>Tiled-horizontal decorator</h1>
 	<p>The 'tiled-horizontal' decorator separates an image into three parts, with the edges displayed at their native size while the middle part is stretched to cover the remaining width of the element. In each of the following examples an image is displayed at its native size first, and then the decorator is applied to it with its element stretched horizontally.</p>
 	<p>The 'tiled-horizontal' decorator separates an image into three parts, with the edges displayed at their native size while the middle part is stretched to cover the remaining width of the element. In each of the following examples an image is displayed at its native size first, and then the decorator is applied to it with its element stretched horizontally.</p>
 	<div class="side-by-side">
 	<div class="side-by-side">
-		<div style="width: 30px; height: 30px; decorator: image( radio );"/>
-		<div style="width: 120px; height: 30px; decorator: tiled-horizontal( demo-radio-l, demo-radio-m, demo-radio-r );"/>
+		<div style="width: 30dp; height: 30dp; decorator: image( radio );"/>
+		<div style="width: 120dp; height: 30dp; decorator: tiled-horizontal( demo-radio-l, demo-radio-m, demo-radio-r );"/>
 	</div>
 	</div>
 	<div class="side-by-side">
 	<div class="side-by-side">
-		<div style="width: 30px; height: 30px; decorator: image( checkbox );"/>
-		<div style="width: 120px; height: 30px; decorator: tiled-horizontal( demo-checkbox-l, demo-checkbox-m, demo-checkbox-r );"/>
+		<div style="width: 30dp; height: 30dp; decorator: image( checkbox );"/>
+		<div style="width: 120dp; height: 30dp; decorator: tiled-horizontal( demo-checkbox-l, demo-checkbox-m, demo-checkbox-r );"/>
 	</div>
 	</div>
-	<div class="side-by-side" width="250px;">
-		<div style="width: 96px; height: 85px; decorator: image( demo-title-bar );"/>
-		<div style="width: 250px; height: 85px; decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );"/>
+	<div class="side-by-side" width="250dp;">
+		<div style="width: 96dp; height: 85dp; decorator: image( demo-title-bar );"/>
+		<div style="width: 250dp; height: 85dp; decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );"/>
 	</div>
 	</div>
 	<p>In the third example we show the same title bar that is used to style the sample windows.</p>
 	<p>In the third example we show the same title bar that is used to style the sample windows.</p>
 	
 	
@@ -609,20 +611,20 @@ progressbar {
 	<h1>Tiled-vertical decorator</h1>
 	<h1>Tiled-vertical decorator</h1>
 	<p>The 'tiled-vertical' decorator behaves like tiled-horizontal, but this time it is stretched vertically.</p>
 	<p>The 'tiled-vertical' decorator behaves like tiled-horizontal, but this time it is stretched vertically.</p>
 	<div class="side-by-side">
 	<div class="side-by-side">
-		<div style="width: 30px; height: 30px; decorator: image( radio );"/>
-		<div style="width: 30px; height: 80px; decorator: tiled-vertical( demo-radio-t, demo-radio-c, demo-radio-b );"/>
+		<div style="width: 30dp; height: 30dp; decorator: image( radio );"/>
+		<div style="width: 30dp; height: 80dp; decorator: tiled-vertical( demo-radio-t, demo-radio-c, demo-radio-b );"/>
 	</div>
 	</div>
 	<div class="side-by-side">
 	<div class="side-by-side">
-		<div style="width: 30px; height: 30px; decorator: image( checkbox );"/>
-		<div style="width: 30px; height: 80px; decorator: tiled-vertical( demo-checkbox-t, demo-checkbox-c, demo-checkbox-b );"/>
+		<div style="width: 30dp; height: 30dp; decorator: image( checkbox );"/>
+		<div style="width: 30dp; height: 80dp; decorator: tiled-vertical( demo-checkbox-t, demo-checkbox-c, demo-checkbox-b );"/>
 	</div>
 	</div>
 	<div class="side-by-side">
 	<div class="side-by-side">
-		<div style="width: 30px; height: 30px; decorator: image( checkbox-checked );"/>
-		<div style="width: 30px; height: 80px; decorator: tiled-vertical( demo-checked-t, demo-checked-c, demo-checked-b );"/>
+		<div style="width: 30dp; height: 30dp; decorator: image( checkbox-checked );"/>
+		<div style="width: 30dp; height: 80dp; decorator: tiled-vertical( demo-checked-t, demo-checked-c, demo-checked-b );"/>
 	</div>
 	</div>
 	<div class="side-by-side">
 	<div class="side-by-side">
-		<div style="width: 51px; height: 39px; decorator: image( icon-help );"/>
-		<div style="width: 51px; height: 80px; decorator: tiled-vertical( demo-help-t, demo-help-c, demo-help-b );"/>
+		<div style="width: 51dp; height: 39dp; decorator: image( icon-help );"/>
+		<div style="width: 51dp; height: 80dp; decorator: tiled-vertical( demo-help-t, demo-help-c, demo-help-b );"/>
 	</div>
 	</div>
 	<p>Clearly, not all images are designed to stretch like this. However, one can certainly envision a usage for the first two examples.</p>
 	<p>Clearly, not all images are designed to stretch like this. However, one can certainly envision a usage for the first two examples.</p>
 	
 	
@@ -637,20 +639,20 @@ progressbar {
 	<p>The 'ninepatch' decorator is similar to the tiled-box decorator in that it splits the image into nine parts. However, only two sprites are used to define all nine tiles, an outer sprite and an inner sprite.</p>
 	<p>The 'ninepatch' decorator is similar to the tiled-box decorator in that it splits the image into nine parts. However, only two sprites are used to define all nine tiles, an outer sprite and an inner sprite.</p>
 	
 	
 	<p>Let us define the outer sprite by the following image, and the inner sprite as the part within the displayed border.</p>
 	<p>Let us define the outer sprite by the following image, and the inner sprite as the part within the displayed border.</p>
-	<div style="position: relative; text-align: left; width: 145px;">
-		<img sprite="textarea"/><img sprite="textarea-inner" style="position: absolute; left: 10px; top: 13px; border: 1px #f0f;"/>
+	<div style="position: relative; text-align: left; width: 145dp;">
+		<img sprite="textarea"/><img sprite="textarea-inner" style="position: absolute; left: 10dp; top: 13dp; border: 1dp #f0f;"/>
 	</div>
 	</div>
 	
 	
 	<p>When the ninepatch decorator is applied and the element is stretched, the following is rendered.</p>
 	<p>When the ninepatch decorator is applied and the element is stretched, the following is rendered.</p>
-	<div style="width: 240px; height: 50px; decorator: ninepatch(textarea, textarea-inner);"/>
+	<div style="width: 240dp; height: 50dp; decorator: ninepatch(textarea, textarea-inner, 1.0);"/>
 	<p>Notice that the corners stay fixed, and the inner sprite is stretched. We can also control the rendered size of the edges, here the left edge is displayed at its native size and the others at half their size.</p>
 	<p>Notice that the corners stay fixed, and the inner sprite is stretched. We can also control the rendered size of the edges, here the left edge is displayed at its native size and the others at half their size.</p>
-	<div style="width: 240px; height: 50px; decorator: ninepatch(textarea, textarea-inner, .5 .5 .5 1);"/>
+	<div style="width: 240dp; height: 50dp; decorator: ninepatch(textarea, textarea-inner, .5 .5 .5 1);"/>
 	
 	
 	<p>If we instead compare this to the image decorator, we see the following.</p>
 	<p>If we instead compare this to the image decorator, we see the following.</p>
-	<div style="width: 240px; height: 50px; decorator: image(textarea);"/>
+	<div style="width: 240dp; height: 50dp; decorator: image(textarea);"/>
 	<p>With the image decorator it looks blurry and its borders are stretched.</p>
 	<p>With the image decorator it looks blurry and its borders are stretched.</p>
 	
 	
-	<div style="width: 850px; margin-left: -175px;">
+	<div style="width: 850dp; margin-left: -175dp;">
 		<h1>Image decorator fit modes</h1>
 		<h1>Image decorator fit modes</h1>
 		<div class="image-mode">
 		<div class="image-mode">
 			<div class="fit-fill"><p>fill</p></div>
 			<div class="fit-fill"><p>fill</p></div>
@@ -687,7 +689,7 @@ progressbar {
 	<h1>Image elements</h1>
 	<h1>Image elements</h1>
 	<div class="center">
 	<div class="center">
 		<img src="../../../assets/high_scores_defender.tga" class="clickable" onclick="change_color"/>
 		<img src="../../../assets/high_scores_defender.tga" class="clickable" onclick="change_color"/>
-		<img sprite="icon-game" style="vertical-align: 10px;"/>
+		<img sprite="icon-game" style="vertical-align: 10dp;"/>
 		<img src="../../../assets/high_scores_defender.tga" style="image-color: #fc5;" rect="0 0 64 64"/>
 		<img src="../../../assets/high_scores_defender.tga" style="image-color: #fc5;" rect="0 0 64 64"/>
 		<img src="../../../assets/high_scores_defender.tga" style="image-color: #9c5;" rect="64 0 64 64"/>
 		<img src="../../../assets/high_scores_defender.tga" style="image-color: #9c5;" rect="64 0 64 64"/>
 	</div>
 	</div>
@@ -695,7 +697,7 @@ progressbar {
 	
 	
 	<h1>Sprite sheets</h1>
 	<h1>Sprite sheets</h1>
 	<p>Sprite sheets are defined by an image source and a collection of sprites, and can be declared in RCSS. Sprites are essentially rectangles into the given image. For example, the following image</p>
 	<p>Sprite sheets are defined by an image source and a collection of sprites, and can be declared in RCSS. Sprites are essentially rectangles into the given image. For example, the following image</p>
-	<img src="../../../assets/invader.tga" rect="0 0 500 435" style="margin-top: 10px; margin-bottom: 10px;"/>
+	<img src="../../../assets/invader.tga" rect="0 0 500 435" style="margin-top: 10dp; margin-bottom: 10dp;"/>
 	<p>is used to render most sprites in this demo. Sprites can be used in decorators and image elements as if they were separate images.</p>
 	<p>is used to render most sprites in this demo. Sprites can be used in decorators and image elements as if they were separate images.</p>
 </panel>
 </panel>
 <tab>Font effects</tab>
 <tab>Font effects</tab>
@@ -756,7 +758,7 @@ progressbar {
 		<option value="in-out">In-Out</option>
 		<option value="in-out">In-Out</option>
 	</select>
 	</select>
 	<div>
 	<div>
-		<input type="range" style="width: 150px; margin-right: 1em;" min="0" max="2" step="0.05" value="0.5" onchange="tween_duration"/> 
+		<input type="range" style="width: 150dp; margin-right: 1em;" min="0" max="2" step="0.05" value="0.5" onchange="tween_duration"/> 
 		Duration <span id="duration">0.50</span> s
 		Duration <span id="duration">0.50</span> s
 	</div>
 	</div>
 	
 	
@@ -816,7 +818,7 @@ progressbar {
 		<div>
 		<div>
 			<textarea cols="25" rows="4" wrap="nowrap" name="message">😍 Hello 🌐 World! 😎</textarea>
 			<textarea cols="25" rows="4" wrap="nowrap" name="message">😍 Hello 🌐 World! 😎</textarea>
 		</div>
 		</div>
-		<div style="margin-bottom: 15px;">
+		<div style="margin-bottom: 15dp;">
 			<input type="submit">Submit</input>
 			<input type="submit">Submit</input>
 		</div>
 		</div>
 		<div id="submit_progress" style="display: none;">
 		<div id="submit_progress" style="display: none;">

+ 6 - 12
Samples/basic/demo/src/main.cpp

@@ -54,17 +54,13 @@ scrollbarhorizontal sliderbar:active { background: #666; }
 class DemoWindow : public Rml::EventListener
 class DemoWindow : public Rml::EventListener
 {
 {
 public:
 public:
-	DemoWindow(const Rml::String &title, const Rml::Vector2f &position, Rml::Context *context)
+	DemoWindow(const Rml::String &title, Rml::Context *context)
 	{
 	{
 		using namespace Rml;
 		using namespace Rml;
 		document = context->LoadDocument("basic/demo/data/demo.rml");
 		document = context->LoadDocument("basic/demo/data/demo.rml");
-		if (document != nullptr)
+		if (document)
 		{
 		{
-			{
-				document->GetElementById("title")->SetInnerRML(title);
-				document->SetProperty(PropertyId::Left, Property(position.x, Property::PX));
-				document->SetProperty(PropertyId::Top, Property(position.y, Property::PX));
-			}
+			document->GetElementById("title")->SetInnerRML(title);
 
 
 			// Add sandbox default text.
 			// Add sandbox default text.
 			if (auto source = static_cast<Rml::ElementFormControl*>(document->GetElementById("sandbox_rml_source")))
 			if (auto source = static_cast<Rml::ElementFormControl*>(document->GetElementById("sandbox_rml_source")))
@@ -465,7 +461,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 #endif
 #endif
 
 
 	const int width = 1600;
 	const int width = 1600;
-	const int height = 900;
+	const int height = 890;
 
 
 	ShellRenderInterfaceOpenGL opengl_renderer;
 	ShellRenderInterfaceOpenGL opengl_renderer;
 	shell_renderer = &opengl_renderer;
 	shell_renderer = &opengl_renderer;
@@ -498,16 +494,14 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
-	
-	context->SetDensityIndependentPixelRatio(1.0f);
+	Shell::SetContext(context);
 
 
 	DemoEventListenerInstancer event_listener_instancer;
 	DemoEventListenerInstancer event_listener_instancer;
 	Rml::Factory::RegisterEventListenerInstancer(&event_listener_instancer);
 	Rml::Factory::RegisterEventListenerInstancer(&event_listener_instancer);
 
 
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 
-	demo_window = Rml::MakeUnique<DemoWindow>("Demo sample", Rml::Vector2f(150, 50), context);
+	demo_window = Rml::MakeUnique<DemoWindow>("Demo sample", context);
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keydown, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keydown, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keyup, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keyup, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Animationend, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Animationend, demo_window.get());

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

@@ -3,18 +3,18 @@ icon
     /* The icons are floated left so they appear left-to-right. */
     /* The icons are floated left so they appear left-to-right. */
     float: left;
     float: left;
     
     
-    /* The padding is added to push the text down to the bottom of the element. The inner dimensions plus the
-       padding come to 100px square. */
-    width: 80px;
-    height: 40px;
-    padding: 60px 10px 0px 10px;
-    margin: 10px;
+    /* The padding is added to push the text down to the bottom of the element.  */
+	box-sizing: border-box;
+    width: 100dp;
+    height: 100dp;
+    padding: 60dp 10dp 0 10dp;
+    margin: 10dp;
     
     
     decorator: image( ../../../assets/present.tga );
     decorator: image( ../../../assets/present.tga );
     
     
-    font-size: 12px;
+    font-size: 12dp;
     text-align: center;
     text-align: center;
-    font-effect: shadow(1px 1px black);
+    font-effect: shadow(1dp 1dp black);
 	
 	
 	cursor: move;
 	cursor: move;
     
     

+ 2 - 2
Samples/basic/drag/data/inventory.rml

@@ -6,8 +6,8 @@
 	<style>
 	<style>
 		body
 		body
 		{
 		{
-			width: 400px;
-			height: 300px;
+			width: 400dp;
+			height: 300dp;
 		}
 		}
 		
 		
 		/* Hide the window icon. */
 		/* Hide the window icon. */

+ 2 - 2
Samples/basic/drag/src/Inventory.cpp

@@ -38,8 +38,8 @@ Inventory::Inventory(const Rml::String& title, const Rml::Vector2f& position, Rm
 	{
 	{
 		using Rml::PropertyId;
 		using Rml::PropertyId;
 		document->GetElementById("title")->SetInnerRML(title);
 		document->GetElementById("title")->SetInnerRML(title);
-		document->SetProperty(PropertyId::Left, Rml::Property(position.x, Rml::Property::PX));
-		document->SetProperty(PropertyId::Top, Rml::Property(position.y, Rml::Property::PX));
+		document->SetProperty(PropertyId::Left, Rml::Property(position.x, Rml::Property::DP));
+		document->SetProperty(PropertyId::Top, Rml::Property(position.y, Rml::Property::DP));
 		document->Show();
 		document->Show();
 	}
 	}
 
 

+ 1 - 1
Samples/basic/drag/src/main.cpp

@@ -107,7 +107,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 

+ 1 - 1
Samples/basic/loaddocument/src/main.cpp

@@ -100,7 +100,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 

+ 2 - 2
Samples/basic/lottie/data/lottie.rml

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 300px;
-				height: 225px;
+				width: 300dp;
+				height: 225dp;
 				
 				
 				margin: auto;
 				margin: auto;
 			}
 			}

+ 1 - 1
Samples/basic/lottie/src/main.cpp

@@ -96,7 +96,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 

+ 26 - 25
Samples/basic/transform/data/transform.rml

@@ -5,8 +5,8 @@
 <style>
 <style>
 body
 body
 {
 {
-	width: 550px;
-	height: 500px;
+	width: 550dp;
+	height: 500dp;
 	/*transform: rotate3d(0,1,0,15deg);*/
 	/*transform: rotate3d(0,1,0,15deg);*/
 }
 }
 
 
@@ -25,7 +25,7 @@ div#title_bar:hover
 spacer
 spacer
 {
 {
 	display: inline-block;
 	display: inline-block;
-	width: 25px;
+	width: 25dp;
 }
 }
 scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 {
 {
@@ -37,25 +37,25 @@ scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
    https://developer.mozilla.org/en-US/docs/Web/CSS/perspective */
    https://developer.mozilla.org/en-US/docs/Web/CSS/perspective */
 
 
 .pers250 {
 .pers250 {
-	perspective: 250px;
+	perspective: 250dp;
 }
 }
 
 
 .pers350 {
 .pers350 {
-	perspective: 350px;
+	perspective: 350dp;
 }
 }
 
 
 .pers500 {
 .pers500 {
-	perspective: 500px;
+	perspective: 500dp;
 }
 }
 
 
 .pers650 {
 .pers650 {
-	perspective: 650px;
+	perspective: 650dp;
 }
 }
 
 
 .container {
 .container {
-	width: 200px;
-	height: 200px;
-	margin: 75px auto;
+	width: 200dp;
+	height: 200dp;
+	margin: 75dp auto;
 	background-color: #a003;
 	background-color: #a003;
 }
 }
 
 
@@ -63,18 +63,18 @@ scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 	width: 100%;
 	width: 100%;
 	height: 100%;
 	height: 100%;
 	position: relative;
 	position: relative;
-	transform: translateZ(50px);
+	transform: translateZ(50dp);
 	perspective-origin: 150% 150%;
 	perspective-origin: 150% 150%;
 }
 }
 
 
 .face {
 .face {
-	left: 50px; top: 50px;
+	left: 50dp; top: 50dp;
 	display: block;
 	display: block;
 	position: absolute;
 	position: absolute;
-	width: 100px;
-	height: 100px;
-	line-height: 100px;
-	font-size: 60px;
+	width: 100dp;
+	height: 100dp;
+	line-height: 100dp;
+	font-size: 60dp;
 	color: white;
 	color: white;
 	text-align: center;
 	text-align: center;
 }
 }
@@ -82,7 +82,7 @@ scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 /* Define each face based on direction */
 /* Define each face based on direction */
 .front {
 .front {
 	background: rgba(0, 0, 0, 160);
 	background: rgba(0, 0, 0, 160);
-	transform: translateZ(50px);
+	transform: translateZ(50dp);
 }
 }
 .front:hover {
 .front:hover {
 	background: rgba(255, 255, 0, 120);
 	background: rgba(255, 255, 0, 120);
@@ -90,23 +90,23 @@ scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 .back {
 .back {
 	background: rgba(0, 255, 0, 255);
 	background: rgba(0, 255, 0, 255);
 	color: black;
 	color: black;
-	transform: rotateY(180deg) translateZ(50px);
+	transform: rotateY(180deg) translateZ(50dp);
 }
 }
 .right {
 .right {
 	background: rgba(196, 0, 0, 200);
 	background: rgba(196, 0, 0, 200);
-	transform: rotateY(90deg) translateZ(50px);
+	transform: rotateY(90deg) translateZ(50dp);
 }
 }
 .left {
 .left {
 	background: rgba(0, 0, 196, 200);
 	background: rgba(0, 0, 196, 200);
-	transform: rotateY(-90deg) translateZ(50px);
+	transform: rotateY(-90deg) translateZ(50dp);
 }
 }
 .top {
 .top {
 	background: rgba(196, 196, 0, 200);
 	background: rgba(196, 196, 0, 200);
-	transform: rotateX(90deg) translateZ(50px);
+	transform: rotateX(90deg) translateZ(50dp);
 }
 }
 .bottom {
 .bottom {
 	background: rgba(196, 0, 196, 200);
 	background: rgba(196, 0, 196, 200);
-	transform: rotateX(-90deg) translateZ(50px);
+	transform: rotateX(-90deg) translateZ(50dp);
 }
 }
 </style>
 </style>
 </head>
 </head>
@@ -120,7 +120,7 @@ scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 		<div class="face right">2</div>
 		<div class="face right">2</div>
 		<div class="face front">1</div>
 		<div class="face front">1</div>
 	</div>
 	</div>
-	perspective: 650px;
+	perspective: 650dp;
 </div>
 </div>
 
 
 <p>Press 'space' to toggle rotation.</p>
 <p>Press 'space' to toggle rotation.</p>
@@ -145,7 +145,7 @@ augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet,
 consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
 consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
 laoreet dolore magna aliquam erat volutpat.</p>
 laoreet dolore magna aliquam erat volutpat.</p>
 
 
-<button style="width: 220px; transform: translateZ(-30px);">A wild button appears!</button>
+<button style="width: 220dp; transform: translateZ(-30dp);">A wild button appears!</button>
 
 
 <p>Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
 <p>Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
 lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure
 lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure
@@ -170,7 +170,8 @@ commodo consequat.</p>
 		<div class="face right">2</div>
 		<div class="face right">2</div>
 		<div class="face front">1</div>
 		<div class="face front">1</div>
 	</div>
 	</div>
-	perspective: 250px; clip: none;
+	perspective: 250dp; clip:none;<br/>
+	(rendered outside the window)
 </div>
 </div>
 
 
 <p>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse
 <p>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse

+ 5 - 5
Samples/basic/transform/src/main.cpp

@@ -46,8 +46,8 @@ public:
 		if (document)
 		if (document)
 		{
 		{
 			document->GetElementById("title")->SetInnerRML(title);
 			document->GetElementById("title")->SetInnerRML(title);
-			document->SetProperty(Rml::PropertyId::Left, Rml::Property(position.x, Rml::Property::PX));
-			document->SetProperty(Rml::PropertyId::Top, Rml::Property(position.y, Rml::Property::PX));
+			document->SetProperty(Rml::PropertyId::Left, Rml::Property(position.x, Rml::Property::DP));
+			document->SetProperty(Rml::PropertyId::Top, Rml::Property(position.y, Rml::Property::DP));
 			document->Show();
 			document->Show();
 		}
 		}
 	}
 	}
@@ -65,7 +65,7 @@ public:
 		if (document && perspective > 0)
 		if (document && perspective > 0)
 		{
 		{
 			std::stringstream s;
 			std::stringstream s;
-			s << "perspective(" << perspective << "px) ";
+			s << "perspective(" << perspective << "dp) ";
 			document->SetProperty("transform", s.str().c_str());
 			document->SetProperty("transform", s.str().c_str());
 		}
 		}
 	}
 	}
@@ -76,7 +76,7 @@ public:
 		{
 		{
 			std::stringstream s;
 			std::stringstream s;
 			if (perspective > 0)
 			if (perspective > 0)
-				s << "perspective(" << perspective << "px) ";
+				s << "perspective(" << perspective << "dp) ";
 			s << "rotate3d(0.0, 1.0, 0.0, " << degrees << "deg)";
 			s << "rotate3d(0.0, 1.0, 0.0, " << degrees << "deg)";
 			document->SetProperty("transform", s.str().c_str());
 			document->SetProperty("transform", s.str().c_str());
 		}
 		}
@@ -184,7 +184,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 

+ 6 - 6
Samples/basic/treeview/data/treeview.rml

@@ -4,8 +4,8 @@
 	<title>Tree View</title>
 	<title>Tree View</title>
 	<style>
 	<style>
 		body {
 		body {
-			width: 450px;
-			height: 400px;
+			width: 450dp;
+			height: 400dp;
 			margin: auto;
 			margin: auto;
 		}
 		}
 		
 		
@@ -19,8 +19,8 @@
 		}
 		}
 		expand {
 		expand {
 			display: inline-block;
 			display: inline-block;
-			vertical-align: -3px;
-			margin-right: 2px;
+			vertical-align: -3dp;
+			margin-right: 2dp;
 		}
 		}
 		tbody tr {
 		tbody tr {
 			height: 1.5em;
 			height: 1.5em;
@@ -38,12 +38,12 @@
 <body template="window">
 <body template="window">
 <table data-model="filebrowser">
 <table data-model="filebrowser">
 	<thead>
 	<thead>
-		<tr><td style="margin-left: 10px; margin-right: 10px;"></td></tr>
+		<tr><td style="margin-left: 10dp; margin-right: 10dp;"></td></tr>
 	</thead>
 	</thead>
 	<tbody>
 	<tbody>
 		<tr data-for="file : files" data-if="file.visible">
 		<tr data-for="file : files" data-if="file.visible">
 			<td>
 			<td>
-				<spacer data-style-width="25 * (1 - file.directory + file.depth) + 'px'"/>
+				<spacer data-style-width="25 * (1 - file.directory + file.depth) + 'dp'"/>
 				<expand data-if="file.directory" data-class-collapsed="file.collapsed" data-event-click="toggle_expand(it_index)"/>
 				<expand data-if="file.directory" data-class-collapsed="file.collapsed" data-event-click="toggle_expand(it_index)"/>
 				{{ file.name }}
 				{{ file.name }}
 			</td>
 			</td>

+ 1 - 1
Samples/basic/treeview/src/main.cpp

@@ -101,7 +101,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");
 
 

+ 14 - 14
Samples/invaders/data/game.rml

@@ -6,8 +6,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				padding: 0px;
-				margin: 0px;
+				padding: 0dp;
+				margin: 0dp;
 				width: 100%;
 				width: 100%;
 				height: 100%;
 				height: 100%;
 
 
@@ -23,11 +23,11 @@
 			
 			
 			div
 			div
 			{
 			{
-				height: 47px;
-				padding: 8px 0px 0px 65px;
-				margin: 0px 20px;
+				height: 47dp;
+				padding: 8dp 0 0 65dp;
+				margin: 0 20dp;
 
 
-				font-size: 20px;
+				font-size: 20dp;
 
 
 				decorator: tiled-horizontal( huditem-l, huditem-c, huditem-r );
 				decorator: tiled-horizontal( huditem-l, huditem-c, huditem-r );
 			}
 			}
@@ -35,36 +35,36 @@
 			div#score_div
 			div#score_div
 			{
 			{
 				float: left;
 				float: left;
-				width: 155px;
+				width: 155dp;
 			}
 			}
 
 
 			div#hiscore_div
 			div#hiscore_div
 			{
 			{
 				float: left;
 				float: left;
-				width: 205px;
+				width: 205dp;
 			}
 			}
 
 
 			div#waves_div
 			div#waves_div
 			{
 			{
 				float: right;
 				float: right;
-				width: 95px;
+				width: 95dp;
 			}
 			}
 
 
 			div#lives_div
 			div#lives_div
 			{
 			{
 				float: right;
 				float: right;
-				width: 80px;
+				width: 80dp;
 			}
 			}
 			
 			
 			icon
 			icon
 			{
 			{
 				display: block;
 				display: block;
 				position: absolute;
 				position: absolute;
-				left: 14px;
-				top: 3px;
+				left: 14dp;
+				top: 3dp;
 
 
-				width: 51px;
-				height: 39px;
+				width: 51dp;
+				height: 39dp;
 			}
 			}
 
 
 			div#score_div icon
 			div#score_div icon

+ 5 - 5
Samples/invaders/data/help.rml

@@ -31,20 +31,20 @@
 		</p>
 		</p>
 		<h1>The X-42</h1>
 		<h1>The X-42</h1>
 		<p>
 		<p>
-			The culmination of <img src="help_defender.tga" style="float: left; margin: -6px -24px;" />decades of research and the pinnacle of Earth's technology, the X-42 'Defender' is the finest weapon mankind has to fight the alien menace. Equipped with the dual-layer ablative tridranium armour, low-velocity depleted-narconium chain-fed belt gun and state-of-the-art liquid-hydrangea turbo-thrusters, it is still going to be nearly impossible for its pilot to secure the safety of mankind.
+			The culmination of <img src="help_defender.tga" style="float: left; margin: -6dp -24dp;" />decades of research and the pinnacle of Earth's technology, the X-42 'Defender' is the finest weapon mankind has to fight the alien menace. Equipped with the dual-layer ablative tridranium armour, low-velocity depleted-narconium chain-fed belt gun and state-of-the-art liquid-hydrangea turbo-thrusters, it is still going to be nearly impossible for its pilot to secure the safety of mankind.
 		</p>
 		</p>
 		<h1>The Invaders</h1>
 		<h1>The Invaders</h1>
 		<p>
 		<p>
-			The most numerous <img src="help_invader_rank1.tga" style="float: left; margin: -4px 0px;" />invader you'll face is a primitive drone that is primarily employed by its Martian overlords in the mines of Cydonia. It is large, ungainly and poorly-armed, so ill-suited to its new role as the backbone of the invasion fleet. However, whatever it lacks in pugilistic prowess it makes up for with numbers. Each drone is worth 10 points.
+			The most numerous <img src="help_invader_rank1.tga" style="float: left; margin: -4dp 0dp;" />invader you'll face is a primitive drone that is primarily employed by its Martian overlords in the mines of Cydonia. It is large, ungainly and poorly-armed, so ill-suited to its new role as the backbone of the invasion fleet. However, whatever it lacks in pugilistic prowess it makes up for with numbers. Each drone is worth 10 points.
 		</p>
 		</p>
 		<p>
 		<p>
-			Behind the drones <img src="help_invader_rank2.tga" style="float: right; margin: -4px 0px;" />stand the formidable berserker units, encased in their zyterium battle-suits and wielding the dreaded Nimbus death-rods. A lone unit is no match for a skilled X-42 pilot, but in large groups they adopt complex flight patterns that can confuse even the best targetting computer. Pick them off and separate them when you can. Each berserker is worth 20 points.
+			Behind the drones <img src="help_invader_rank2.tga" style="float: right; margin: -4dp 0dp;" />stand the formidable berserker units, encased in their zyterium battle-suits and wielding the dreaded Nimbus death-rods. A lone unit is no match for a skilled X-42 pilot, but in large groups they adopt complex flight patterns that can confuse even the best targetting computer. Pick them off and separate them when you can. Each berserker is worth 20 points.
 		</p>
 		</p>
 		<p>
 		<p>
-			The dreaded commander <img src="help_invader_rank3.tga" style="float: left; margin: -4px 0px;" />death-droids lie at the back of every Martian wave. Small, nimble and deadly, these ships are the true test of an X-42 pilot's abilities. Consider yourself warned, and watch out especially for their mind control attack! Each droid is worth 40 points.
+			The dreaded commander <img src="help_invader_rank3.tga" style="float: left; margin: -4dp 0dp;" />death-droids lie at the back of every Martian wave. Small, nimble and deadly, these ships are the true test of an X-42 pilot's abilities. Consider yourself warned, and watch out especially for their mind control attack! Each droid is worth 40 points.
 		</p>
 		</p>
 		<p>
 		<p>
-			Occasionally one of the <img src="help_invader_mothership.tga" style="float: right; margin: -6px -12px;" /> invasion motherships will drop into low-orbit to provide the Martian Overbrain with a close look at the progress of the battle; this is when they are most vulnerable, destroy them if you can! The loss of even a single mothership will be keenly felt by the fleet. The points value of each mothership is variable, depending on the seniority of its command synapse.
+			Occasionally one of the <img src="help_invader_mothership.tga" style="float: right; margin: -6dp -12dp;" /> invasion motherships will drop into low-orbit to provide the Martian Overbrain with a close look at the progress of the battle; this is when they are most vulnerable, destroy them if you can! The loss of even a single mothership will be keenly felt by the fleet. The points value of each mothership is variable, depending on the seniority of its command synapse.
 		</p>
 		</p>
 		<p>
 		<p>
 			Destroy all the invaders in each wave before any get past your ship to invade Earth, unleash their deadly toxin and wipe out all of humanity!
 			Destroy all the invaders in each wave before any get past your ship to invade Earth, unleash their deadly toxin and wipe out all of humanity!

+ 10 - 10
Samples/invaders/data/high_score.rml

@@ -5,8 +5,8 @@
 	<style>
 	<style>
 		body
 		body
 		{
 		{
-			width: 440px;
-			height: 440px;
+			width: 440dp;
+			height: 440dp;
 			
 			
 			margin: auto;
 			margin: auto;
 		}
 		}
@@ -18,18 +18,18 @@
 		defender
 		defender
 		{
 		{
 			display: inline-block;
 			display: inline-block;
-			width: 64px;
-			height: 16px;
+			width: 64dp;
+			height: 16dp;
 			
 			
 			decorator: defender( high_scores_defender.tga );
 			decorator: defender( high_scores_defender.tga );
 		}
 		}
 		tbody tr {
 		tbody tr {
-			height: 30px;
+			height: 30dp;
 		}
 		}
 		tbody td
 		tbody td
 		{
 		{
-			padding-top: 5px;
-			height: 30px;
+			padding-top: 5dp;
+			height: 30dp;
 			white-space: nowrap;
 			white-space: nowrap;
 			overflow: hidden;
 			overflow: hidden;
 		}
 		}
@@ -39,10 +39,10 @@
 	<table data-model="high_scores">
 	<table data-model="high_scores">
 		<thead>
 		<thead>
 			<tr>
 			<tr>
-				<td style="width: 200%; margin-left: 10px;">Pilot</td>
-				<td style="min-width: 64px;">Ship</td>
+				<td style="width: 200%; margin-left: 10dp;">Pilot</td>
+				<td style="min-width: 64dp;">Ship</td>
 				<td>Wave</td>
 				<td>Wave</td>
-				<td style="min-width: 64px;">Score</td>
+				<td style="min-width: 64dp;">Score</td>
 			</tr>
 			</tr>
 		</thead>
 		</thead>
 		<tbody>
 		<tbody>

+ 2 - 2
Samples/invaders/data/logo.rml

@@ -12,8 +12,8 @@
 			#rifm_logo
 			#rifm_logo
 			{
 			{
 				position: absolute;
 				position: absolute;
-				left: 25px;
-				top: 25px;
+				left: 25dp;
+				top: 25dp;
 			}
 			}
 		</style>
 		</style>
 	</head>
 	</head>

+ 2 - 2
Samples/invaders/data/main_menu.rml

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 300px;
-				height: 225px;
+				width: 300dp;
+				height: 225dp;
 
 
 				margin: auto;
 				margin: auto;
 			}
 			}

+ 3 - 3
Samples/invaders/data/options.rml

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 350px;
-				height: 330px;
+				width: 350dp;
+				height: 330dp;
 				
 				
 				margin: auto;
 				margin: auto;
 			}
 			}
@@ -19,7 +19,7 @@
 
 
 			form div
 			form div
 			{
 			{
-				width: 200px;
+				width: 200dp;
 				margin: auto;
 				margin: auto;
 			}
 			}
 		</style>
 		</style>

+ 2 - 2
Samples/invaders/data/pause.rml

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 350px;
-				height: 135px;
+				width: 350dp;
+				height: 135dp;
 				
 				
 				margin: auto;
 				margin: auto;
 			}
 			}

+ 6 - 6
Samples/invaders/data/start_game.rml

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 300px;
-				height: 225px;
+				width: 300dp;
+				height: 225dp;
 				
 				
 				margin: auto;
 				margin: auto;
 			}
 			}
@@ -18,15 +18,15 @@
 			
 			
 			form div
 			form div
 			{
 			{
-				width: 200px;
+				width: 200dp;
 				margin: auto;
 				margin: auto;
 			}
 			}
 			color
 			color
 			{
 			{
 				display: inline-block;
 				display: inline-block;
-				width: 9px;
-				height: 9px;
-				border: 1px #666;
+				width: 9dp;
+				height: 9dp;
+				border: 1dp #666;
 				margin-right: 0.5em;
 				margin-right: 0.5em;
 			}
 			}
 		</style>
 		</style>

+ 2 - 2
Samples/invaders/src/DecoratorDefender.cpp

@@ -36,9 +36,9 @@ DecoratorDefender::~DecoratorDefender()
 {
 {
 }
 }
 
 
-bool DecoratorDefender::Initialise(const Rml::String& image_source, const Rml::String& image_path)
+bool DecoratorDefender::Initialise(const Rml::Texture& texture)
 {
 {
-	image_index = LoadTexture(image_source, image_path);
+	image_index = AddTexture(texture);
 	if (image_index == -1)
 	if (image_index == -1)
 	{
 	{
 		return false;
 		return false;

+ 1 - 1
Samples/invaders/src/DecoratorDefender.h

@@ -36,7 +36,7 @@ class DecoratorDefender : public Rml::Decorator
 public:
 public:
 	virtual ~DecoratorDefender();
 	virtual ~DecoratorDefender();
 
 
-	bool Initialise(const Rml::String& image_source, const Rml::String& image_path);
+	bool Initialise(const Rml::Texture& texture);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// @param element[in] The newly decorated element.
 	/// @param element[in] The newly decorated element.

+ 3 - 5
Samples/invaders/src/DecoratorInstancerDefender.cpp

@@ -44,16 +44,14 @@ DecoratorInstancerDefender::~DecoratorInstancerDefender()
 
 
 // Instances a decorator given the property tag and attributes from the RCSS file.
 // Instances a decorator given the property tag and attributes from the RCSS file.
 Rml::SharedPtr<Rml::Decorator> DecoratorInstancerDefender::InstanceDecorator(const Rml::String& /*name*/,
 Rml::SharedPtr<Rml::Decorator> DecoratorInstancerDefender::InstanceDecorator(const Rml::String& /*name*/,
-	const Rml::PropertyDictionary& properties, const Rml::DecoratorInstancerInterface& /*instancer_interface*/)
+	const Rml::PropertyDictionary& properties, const Rml::DecoratorInstancerInterface& instancer_interface)
 {
 {
 	const Rml::Property* image_source_property = properties.GetProperty(id_image_src);
 	const Rml::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rml::String image_source = image_source_property->Get< Rml::String >();
 	Rml::String image_source = image_source_property->Get< Rml::String >();
-	Rml::String source_path;
-	if (auto & source = image_source_property->source)
-		source_path = source->path;
+	Rml::Texture texture = instancer_interface.GetTexture(image_source);
 
 
 	auto decorator = Rml::MakeShared<DecoratorDefender>();
 	auto decorator = Rml::MakeShared<DecoratorDefender>();
-	if (decorator->Initialise(image_source, source_path))
+	if (decorator->Initialise(texture))
 		return decorator;
 		return decorator;
 	
 	
 	return nullptr;
 	return nullptr;

+ 3 - 3
Samples/invaders/src/Defender.cpp

@@ -103,18 +103,18 @@ void Defender::Update()
 	}
 	}
 }
 }
 
 
-void Defender::Render()
+void Defender::Render(float dp_ratio)
 {
 {
 	glColor4ubv(GameDetails::GetDefenderColour());
 	glColor4ubv(GameDetails::GetDefenderColour());
 
 
 	// Render our sprite if rendering is enabled
 	// Render our sprite if rendering is enabled
 	if (render)
 	if (render)
-		defender_sprite.Render(Rml::Vector2f(position.x, position.y));
+		defender_sprite.Render(position, dp_ratio);
 
 
 	// Update the bullet, doing collision detection
 	// Update the bullet, doing collision detection
 	if (bullet_in_flight)
 	if (bullet_in_flight)
 	{
 	{
-		bullet_sprite.Render(Rml::Vector2f(bullet_position.x, bullet_position.y));
+		bullet_sprite.Render(bullet_position, dp_ratio);
 
 
 		// Check if we hit the shields
 		// Check if we hit the shields
 		for (int i = 0; i < game->GetNumShields(); i++)
 		for (int i = 0; i < game->GetNumShields(); i++)

+ 1 - 1
Samples/invaders/src/Defender.h

@@ -48,7 +48,7 @@ public:
 	/// Update the defender state.
 	/// Update the defender state.
 	void Update();
 	void Update();
 	/// Render the defender.
 	/// Render the defender.
-	void Render();
+	void Render(float dp_ratio);
 
 
 	/// Move the defender left.
 	/// Move the defender left.
 	void StartMove(float direction);	
 	void StartMove(float direction);	

+ 2 - 1
Samples/invaders/src/ElementGame.cpp

@@ -27,6 +27,7 @@
  */
  */
 
 
 #include "ElementGame.h"
 #include "ElementGame.h"
+#include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/ElementDocument.h>
 #include <RmlUi/Core/ElementDocument.h>
 #include <RmlUi/Core/Input.h>
 #include <RmlUi/Core/Input.h>
 #include "Defender.h"
 #include "Defender.h"
@@ -92,7 +93,7 @@ void ElementGame::OnUpdate()
 // Renders the game.
 // Renders the game.
 void ElementGame::OnRender()
 void ElementGame::OnRender()
 {
 {
-	game->Render();
+	game->Render(GetContext()->GetDensityIndependentPixelRatio());
 }
 }
 
 
 void ElementGame::OnChildAdd(Rml::Element* element)
 void ElementGame::OnChildAdd(Rml::Element* element)

+ 4 - 4
Samples/invaders/src/Game.cpp

@@ -142,7 +142,7 @@ void Game::Update()
 	}
 	}
 }
 }
 
 
-void Game::Render()
+void Game::Render(float dp_ratio)
 {	
 {	
 	if (defender_lives <= 0)
 	if (defender_lives <= 0)
 		return;
 		return;
@@ -150,7 +150,7 @@ void Game::Render()
 	// Render all available shields
 	// Render all available shields
 	for (int i = 0; i < NUM_SHIELDS; i++)
 	for (int i = 0; i < NUM_SHIELDS; i++)
 	{
 	{
-		shields[i]->Render();
+		shields[i]->Render(dp_ratio);
 	}
 	}
 
 
 	glEnable(GL_TEXTURE_2D);
 	glEnable(GL_TEXTURE_2D);
@@ -161,10 +161,10 @@ void Game::Render()
 	// Render all available invaders
 	// Render all available invaders
 	for (int i = 0; i < NUM_INVADERS + 1; i++)
 	for (int i = 0; i < NUM_INVADERS + 1; i++)
 	{
 	{
-		invaders[i]->Render();
+		invaders[i]->Render(dp_ratio);
 	}
 	}
 	
 	
-	defender->Render();
+	defender->Render(dp_ratio);
 
 
 	glEnd();
 	glEnd();
 }
 }

+ 1 - 1
Samples/invaders/src/Game.h

@@ -58,7 +58,7 @@ public:
 	void Update();
 	void Update();
 
 
 	/// Render the game
 	/// Render the game
-	void Render();
+	void Render(float dp_ratio);
 
 
 	/// Access the defender
 	/// Access the defender
 	Defender* GetDefender();
 	Defender* GetDefender();

+ 3 - 3
Samples/invaders/src/Invader.cpp

@@ -182,7 +182,7 @@ void Invader::UpdateAnimation()
 	}
 	}
 }
 }
 
 
-void Invader::Render()
+void Invader::Render(float dp_ratio)
 {
 {
 	if (type == MOTHERSHIP)
 	if (type == MOTHERSHIP)
 	{
 	{
@@ -192,11 +192,11 @@ void Invader::Render()
 	int sprite_offset = Rml::Math::RealToInteger((invader_sprites[sprite_index].dimensions.x - 48) / 2);
 	int sprite_offset = Rml::Math::RealToInteger((invader_sprites[sprite_index].dimensions.x - 48) / 2);
 
 
 	if (state != DEAD)
 	if (state != DEAD)
-		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y));
+		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y), dp_ratio);
 	
 	
 	if (bomb != NONE)
 	if (bomb != NONE)
 	{
 	{
-		bomb_sprites[bomb_animation_frame].Render(bomb_position);
+		bomb_sprites[bomb_animation_frame].Render(bomb_position, dp_ratio);
 	}
 	}
 
 
 	if (type == MOTHERSHIP)
 	if (type == MOTHERSHIP)

+ 1 - 1
Samples/invaders/src/Invader.h

@@ -60,7 +60,7 @@ public:
 	virtual void Update();
 	virtual void Update();
 
 
 	/// Render the invader
 	/// Render the invader
-	void Render();
+	void Render(float dp_ratio);
 
 
 	/// Update the invaders animation
 	/// Update the invaders animation
 	void UpdateAnimation();
 	void UpdateAnimation();

+ 6 - 3
Samples/invaders/src/Shield.cpp

@@ -119,11 +119,14 @@ const Rml::Vector2f& Shield::GetPosition() const
 	return position;
 	return position;
 }
 }
 
 
-void Shield::Render()
+void Shield::Render(float dp_ratio)
 {
 {
 	if (health > 0)
 	if (health > 0)
 	{
 	{
-		glPointSize((GLfloat) PIXEL_SIZE);
+		const Rml::Vector2f scaled_position = (dp_ratio * position).Round();
+		const int scaled_pixel = Rml::Math::RoundUpToInteger(PIXEL_SIZE * dp_ratio);
+
+		glPointSize((GLfloat)scaled_pixel);
 		glDisable(GL_TEXTURE_2D);
 		glDisable(GL_TEXTURE_2D);
 		glColor4ubv(GameDetails::GetDefenderColour());
 		glColor4ubv(GameDetails::GetDefenderColour());
 
 
@@ -135,7 +138,7 @@ void Shield::Render()
 			{
 			{
 				if (shield_cells[i][j] == ON)
 				if (shield_cells[i][j] == ON)
 				{
 				{
-					Rml::Vector2f cell_position = position + Rml::Vector2f((float) (PIXEL_SIZE * i), (float) (PIXEL_SIZE * j));
+					Rml::Vector2f cell_position = scaled_position + Rml::Vector2f(float(scaled_pixel * i), float(scaled_pixel * j));
 					glVertex2f(cell_position.x, cell_position.y);
 					glVertex2f(cell_position.x, cell_position.y);
 				}
 				}
 			}
 			}

+ 1 - 1
Samples/invaders/src/Shield.h

@@ -62,7 +62,7 @@ public:
 	const Rml::Vector2f& GetPosition() const;
 	const Rml::Vector2f& GetPosition() const;
 
 
 	/// Render the shield.
 	/// Render the shield.
-	void Render();
+	void Render(float dp_ratio);
 
 
 	/// Returns true if the position hits the shield
 	/// Returns true if the position hits the shield
 	/// If a hit is detected, will degrade the shield.
 	/// If a hit is detected, will degrade the shield.

+ 10 - 4
Samples/invaders/src/Sprite.cpp

@@ -27,6 +27,7 @@
  */
  */
 
 
 #include "Sprite.h"
 #include "Sprite.h"
+#include <RmlUi/Core/Math.h>
 #include <ShellOpenGL.h>
 #include <ShellOpenGL.h>
 
 
 Sprite::Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord) : dimensions(dimensions), top_left_texcoord(top_left_texcoord), bottom_right_texcoord(bottom_right_texcoord)
 Sprite::Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord) : dimensions(dimensions), top_left_texcoord(top_left_texcoord), bottom_right_texcoord(bottom_right_texcoord)
@@ -37,17 +38,22 @@ Sprite::~Sprite()
 {
 {
 }
 }
 
 
-void Sprite::Render(const Rml::Vector2f& position)
+void Sprite::Render(Rml::Vector2f position, const float dp_ratio)
 {
 {
+	position = (dp_ratio * position);
+	Rml::Vector2f dimensions_px = dp_ratio * dimensions;
+
+	Rml::Math::SnapToPixelGrid(position, dimensions_px);
+
 	glTexCoord2f(top_left_texcoord.x, top_left_texcoord.y);
 	glTexCoord2f(top_left_texcoord.x, top_left_texcoord.y);
 	glVertex2f(position.x, position.y);
 	glVertex2f(position.x, position.y);
 
 
 	glTexCoord2f(top_left_texcoord.x, bottom_right_texcoord.y);
 	glTexCoord2f(top_left_texcoord.x, bottom_right_texcoord.y);
-	glVertex2f(position.x, position.y + dimensions.y);
+	glVertex2f(position.x, position.y + dimensions_px.y);
 
 
 	glTexCoord2f(bottom_right_texcoord.x, bottom_right_texcoord.y);
 	glTexCoord2f(bottom_right_texcoord.x, bottom_right_texcoord.y);
-	glVertex2f(position.x + dimensions.x, position.y + dimensions.y);
+	glVertex2f(position.x + dimensions_px.x, position.y + dimensions_px.y);
 
 
 	glTexCoord2f(bottom_right_texcoord.x, top_left_texcoord.y);
 	glTexCoord2f(bottom_right_texcoord.x, top_left_texcoord.y);
-	glVertex2f(position.x + dimensions.x, position.y);
+	glVertex2f(position.x + dimensions_px.x, position.y);
 }
 }

+ 1 - 1
Samples/invaders/src/Sprite.h

@@ -41,7 +41,7 @@ public:
 	Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord);
 	Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord);
 	~Sprite();
 	~Sprite();
 
 
-	void Render(const Rml::Vector2f& position);
+	void Render(Rml::Vector2f position, float dp_ratio);
 
 
 	Rml::Vector2f dimensions;
 	Rml::Vector2f dimensions;
 	Rml::Vector2f top_left_texcoord;
 	Rml::Vector2f top_left_texcoord;

+ 1 - 1
Samples/invaders/src/main.cpp

@@ -110,7 +110,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	// Initialise the RmlUi debugger.
 	// Initialise the RmlUi debugger.
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	// Load the font faces required for Invaders.
 	// Load the font faces required for Invaders.
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");

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

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				padding: 0px;
-				margin: 0px;
+				padding: 0dp;
+				margin: 0dp;
 				width: 100%;
 				width: 100%;
 				height: 100%;
 				height: 100%;
 
 
@@ -22,11 +22,11 @@
 
 
 			div
 			div
 			{
 			{
-				height: 47px;
-				padding: 8px 0px 0px 65px;
-				margin: 0px 20px;
+				height: 47dp;
+				padding: 8dp 0dp 0dp 65dp;
+				margin: 0dp 20dp;
 
 
-				font-size: 20px;
+				font-size: 20dp;
 
 
 				decorator: tiled-horizontal( huditem-l, huditem-c, huditem-r );
 				decorator: tiled-horizontal( huditem-l, huditem-c, huditem-r );
 			}
 			}
@@ -34,36 +34,36 @@
 			div#score_div
 			div#score_div
 			{
 			{
 				float: left;
 				float: left;
-				width: 155px;
+				width: 155dp;
 			}
 			}
 
 
 			div#hiscore_div
 			div#hiscore_div
 			{
 			{
 				float: left;
 				float: left;
-				width: 205px;
+				width: 205dp;
 			}
 			}
 
 
 			div#waves_div
 			div#waves_div
 			{
 			{
 				float: right;
 				float: right;
-				width: 95px;
+				width: 95dp;
 			}
 			}
 
 
 			div#lives_div
 			div#lives_div
 			{
 			{
 				float: right;
 				float: right;
-				width: 80px;
+				width: 80dp;
 			}
 			}
 
 
 			icon
 			icon
 			{
 			{
 				display: block;
 				display: block;
 				position: absolute;
 				position: absolute;
-				left: 14px;
-				top: 3px;
+				left: 14dp;
+				top: 3dp;
 
 
-				width: 51px;
-				height: 39px;
+				width: 51dp;
+				height: 39dp;
 			}
 			}
 
 
 			div#score_div icon
 			div#score_div icon

+ 5 - 5
Samples/luainvaders/data/help.rml

@@ -31,20 +31,20 @@
 		</p>
 		</p>
 		<h1>The X-42</h1>
 		<h1>The X-42</h1>
 		<p>
 		<p>
-			The culmination of <img src="help_defender.tga" style="float: left; margin: -6px -24px;" />decades of research and the pinnacle of Earth's technology, the X-42 'Defender' is the finest weapon mankind has to fight the alien menace. Equipped with the dual-layer ablative tridranium armour, low-velocity depleted-narconium chain-fed belt gun and state-of-the-art liquid-hydrangea turbo-thrusters, it is still going to be nearly impossible for its pilot to secure the safety of mankind.
+			The culmination of <img src="help_defender.tga" style="float: left; margin: -6dp -24dp;" />decades of research and the pinnacle of Earth's technology, the X-42 'Defender' is the finest weapon mankind has to fight the alien menace. Equipped with the dual-layer ablative tridranium armour, low-velocity depleted-narconium chain-fed belt gun and state-of-the-art liquid-hydrangea turbo-thrusters, it is still going to be nearly impossible for its pilot to secure the safety of mankind.
 		</p>
 		</p>
 		<h1>The Invaders</h1>
 		<h1>The Invaders</h1>
 		<p>
 		<p>
-			The most numerous <img src="help_invader_rank1.tga" style="float: left; margin: -4px 0px;" />invader you'll face is a primitive drone that is primarily employed by its Martian overlords in the mines of Cydonia. It is large, ungainly and poorly-armed, so ill-suited to its new role as the backbone of the invasion fleet. However, whatever it lacks in pugilistic prowess it makes up for with numbers. Each drone is worth 10 points.
+			The most numerous <img src="help_invader_rank1.tga" style="float: left; margin: -4dp 0dp;" />invader you'll face is a primitive drone that is primarily employed by its Martian overlords in the mines of Cydonia. It is large, ungainly and poorly-armed, so ill-suited to its new role as the backbone of the invasion fleet. However, whatever it lacks in pugilistic prowess it makes up for with numbers. Each drone is worth 10 points.
 		</p>
 		</p>
 		<p>
 		<p>
-			Behind the drones <img src="help_invader_rank2.tga" style="float: right; margin: -4px 0px;" />stand the formidable berserker units, encased in their zyterium battle-suits and wielding the dreaded Nimbus death-rods. A lone unit is no match for a skilled X-42 pilot, but in large groups they adopt complex flight patterns that can confuse even the best targetting computer. Pick them off and separate them when you can. Each berserker is worth 20 points.
+			Behind the drones <img src="help_invader_rank2.tga" style="float: right; margin: -4dp 0dp;" />stand the formidable berserker units, encased in their zyterium battle-suits and wielding the dreaded Nimbus death-rods. A lone unit is no match for a skilled X-42 pilot, but in large groups they adopt complex flight patterns that can confuse even the best targetting computer. Pick them off and separate them when you can. Each berserker is worth 20 points.
 		</p>
 		</p>
 		<p>
 		<p>
-			The dreaded commander <img src="help_invader_rank3.tga" style="float: left; margin: -4px 0px;" />death-droids lie at the back of every Martian wave. Small, nimble and deadly, these ships are the true test of an X-42 pilot's abilities. Consider yourself warned, and watch out especially for their mind control attack! Each droid is worth 40 points.
+			The dreaded commander <img src="help_invader_rank3.tga" style="float: left; margin: -4dp 0dp;" />death-droids lie at the back of every Martian wave. Small, nimble and deadly, these ships are the true test of an X-42 pilot's abilities. Consider yourself warned, and watch out especially for their mind control attack! Each droid is worth 40 points.
 		</p>
 		</p>
 		<p>
 		<p>
-			Occasionally one of the <img src="help_invader_mothership.tga" style="float: right; margin: -6px -12px;" /> invasion motherships will drop into low-orbit to provide the Martian Overbrain with a close look at the progress of the battle; this is when they are most vulnerable, destroy them if you can! The loss of even a single mothership will be keenly felt by the fleet. The points value of each mothership is variable, depending on the seniority of its command synapse.
+			Occasionally one of the <img src="help_invader_mothership.tga" style="float: right; margin: -6dp -12dp;" /> invasion motherships will drop into low-orbit to provide the Martian Overbrain with a close look at the progress of the battle; this is when they are most vulnerable, destroy them if you can! The loss of even a single mothership will be keenly felt by the fleet. The points value of each mothership is variable, depending on the seniority of its command synapse.
 		</p>
 		</p>
 		<p>
 		<p>
 			Destroy all the invaders in each wave before any get past your ship to invade Earth, unleash their deadly toxin and wipe out all of humanity!
 			Destroy all the invaders in each wave before any get past your ship to invade Earth, unleash their deadly toxin and wipe out all of humanity!

+ 10 - 10
Samples/luainvaders/data/high_score.rml

@@ -5,8 +5,8 @@
 	<style>
 	<style>
 		body
 		body
 		{
 		{
-			width: 440px;
-			height: 440px;
+			width: 440dp;
+			height: 440dp;
 			
 			
 			margin: auto;
 			margin: auto;
 		}
 		}
@@ -18,18 +18,18 @@
 		defender
 		defender
 		{
 		{
 			display: inline-block;
 			display: inline-block;
-			width: 64px;
-			height: 16px;
+			width: 64dp;
+			height: 16dp;
 			
 			
 			decorator: defender( high_scores_defender.tga );
 			decorator: defender( high_scores_defender.tga );
 		}
 		}
 		tbody tr {
 		tbody tr {
-			height: 30px;
+			height: 30dp;
 		}
 		}
 		tbody td
 		tbody td
 		{
 		{
-			padding-top: 5px;
-			height: 30px;
+			padding-top: 5dp;
+			height: 30dp;
 			white-space: nowrap;
 			white-space: nowrap;
 			overflow: hidden;
 			overflow: hidden;
 		}
 		}
@@ -48,10 +48,10 @@ end
 	<table data-model="high_scores">
 	<table data-model="high_scores">
 		<thead>
 		<thead>
 			<tr>
 			<tr>
-				<td style="width: 200%; margin-left: 10px;">Pilot</td>
-				<td style="min-width: 64px;">Ship</td>
+				<td style="width: 200%; margin-left: 10dp;">Pilot</td>
+				<td style="min-width: 64dp;">Ship</td>
 				<td>Wave</td>
 				<td>Wave</td>
-				<td style="min-width: 64px;">Score</td>
+				<td style="min-width: 64dp;">Score</td>
 			</tr>
 			</tr>
 		</thead>
 		</thead>
 		<tbody>
 		<tbody>

+ 2 - 2
Samples/luainvaders/data/logo.rml

@@ -12,8 +12,8 @@
 			#rifm_logo
 			#rifm_logo
 			{
 			{
 				position: absolute;
 				position: absolute;
-				left: 25px;
-				top: 25px;
+				left: 25dp;
+				top: 25dp;
 			}
 			}
 		</style>
 		</style>
 	</head>
 	</head>

+ 2 - 2
Samples/luainvaders/data/main_menu.rml

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 300px;
-				height: 225px;
+				width: 300dp;
+				height: 225dp;
 
 
 				margin: auto;
 				margin: auto;
 			}
 			}

+ 3 - 3
Samples/luainvaders/data/options.rml

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 350px;
-				height: 350px;
+				width: 350dp;
+				height: 350dp;
 				
 				
 				margin: auto;
 				margin: auto;
 			}
 			}
@@ -19,7 +19,7 @@
 
 
 			form div
 			form div
 			{
 			{
-				width: 200px;
+				width: 200dp;
 				margin: auto;
 				margin: auto;
 			}
 			}
 		</style>
 		</style>

+ 2 - 2
Samples/luainvaders/data/pause.rml

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 350px;
-				height: 135px;
+				width: 350dp;
+				height: 135dp;
 				
 				
 				margin: auto;
 				margin: auto;
 			}
 			}

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

@@ -5,8 +5,8 @@
 		<style>
 		<style>
 			body
 			body
 			{
 			{
-				width: 300px;
-				height: 225px;
+				width: 300dp;
+				height: 225dp;
 				
 				
 				margin: auto;
 				margin: auto;
 			}
 			}
@@ -18,15 +18,15 @@
 			
 			
 			form div
 			form div
 			{
 			{
-				width: 200px;
+				width: 200dp;
 				margin: auto;
 				margin: auto;
 			}
 			}
 			color
 			color
 			{
 			{
 				display: inline-block;
 				display: inline-block;
-				width: 9px;
-				height: 9px;
-				border: 1px #666;
+				width: 9dp;
+				height: 9dp;
+				border: 1dp #666;
 				margin-right: 0.5em;
 				margin-right: 0.5em;
 			}
 			}
 		</style>
 		</style>

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

@@ -19,6 +19,6 @@ function Window.LoadMenu(name,document)
 end
 end
 	</script>
 	</script>
 </head>
 </head>
-<body template="window" onload="Window.OnWindowLoad(document)">
+<body template="window">
 </body>
 </body>
 </template>
 </template>

+ 2 - 2
Samples/luainvaders/src/DecoratorDefender.cpp

@@ -36,9 +36,9 @@ DecoratorDefender::~DecoratorDefender()
 {
 {
 }
 }
 
 
-bool DecoratorDefender::Initialise(const Rml::String& image_source, const Rml::String& image_path)
+bool DecoratorDefender::Initialise(const Rml::Texture& texture)
 {
 {
-	image_index = LoadTexture(image_source, image_path);
+	image_index = AddTexture(texture);
 	if (image_index == -1)
 	if (image_index == -1)
 	{
 	{
 		return false;
 		return false;

+ 1 - 1
Samples/luainvaders/src/DecoratorDefender.h

@@ -36,7 +36,7 @@ class DecoratorDefender : public Rml::Decorator
 public:
 public:
 	virtual ~DecoratorDefender();
 	virtual ~DecoratorDefender();
 
 
-	bool Initialise(const Rml::String& image_source, const Rml::String& image_path);
+	bool Initialise(const Rml::Texture& texture);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// @param element[in] The newly decorated element.
 	/// @param element[in] The newly decorated element.

+ 3 - 5
Samples/luainvaders/src/DecoratorInstancerDefender.cpp

@@ -44,16 +44,14 @@ DecoratorInstancerDefender::~DecoratorInstancerDefender()
 
 
 // Instances a decorator given the property tag and attributes from the RCSS file.
 // Instances a decorator given the property tag and attributes from the RCSS file.
 Rml::SharedPtr<Rml::Decorator> DecoratorInstancerDefender::InstanceDecorator(const Rml::String& /*name*/,
 Rml::SharedPtr<Rml::Decorator> DecoratorInstancerDefender::InstanceDecorator(const Rml::String& /*name*/,
-	const Rml::PropertyDictionary& properties, const Rml::DecoratorInstancerInterface& /*instancer_interface*/)
+	const Rml::PropertyDictionary& properties, const Rml::DecoratorInstancerInterface& instancer_interface)
 {
 {
 	const Rml::Property* image_source_property = properties.GetProperty(id_image_src);
 	const Rml::Property* image_source_property = properties.GetProperty(id_image_src);
 	Rml::String image_source = image_source_property->Get< Rml::String >();
 	Rml::String image_source = image_source_property->Get< Rml::String >();
-	Rml::String source_path;
-	if (auto & source = image_source_property->source)
-		source_path = source->path;
+	Rml::Texture texture = instancer_interface.GetTexture(image_source);
 
 
 	auto decorator = Rml::MakeShared<DecoratorDefender>();
 	auto decorator = Rml::MakeShared<DecoratorDefender>();
-	if (decorator->Initialise(image_source, source_path))
+	if (decorator->Initialise(texture))
 		return decorator;
 		return decorator;
 
 
 	return nullptr;
 	return nullptr;

+ 3 - 3
Samples/luainvaders/src/Defender.cpp

@@ -103,18 +103,18 @@ void Defender::Update()
 	}
 	}
 }
 }
 
 
-void Defender::Render()
+void Defender::Render(float dp_ratio)
 {
 {
 	glColor4ubv(GameDetails::GetDefenderColour());
 	glColor4ubv(GameDetails::GetDefenderColour());
 
 
 	// Render our sprite if rendering is enabled
 	// Render our sprite if rendering is enabled
 	if (render)
 	if (render)
-		defender_sprite.Render(Rml::Vector2f(position.x, position.y));
+		defender_sprite.Render(position, dp_ratio);
 
 
 	// Update the bullet, doing collision detection
 	// Update the bullet, doing collision detection
 	if (bullet_in_flight)
 	if (bullet_in_flight)
 	{
 	{
-		bullet_sprite.Render(Rml::Vector2f(bullet_position.x, bullet_position.y));
+		bullet_sprite.Render(bullet_position, dp_ratio);
 
 
 		// Check if we hit the shields
 		// Check if we hit the shields
 		for (int i = 0; i < game->GetNumShields(); i++)
 		for (int i = 0; i < game->GetNumShields(); i++)

+ 1 - 1
Samples/luainvaders/src/Defender.h

@@ -48,7 +48,7 @@ public:
 	/// Update the defender state.
 	/// Update the defender state.
 	void Update();
 	void Update();
 	/// Render the defender.
 	/// Render the defender.
-	void Render();
+	void Render(float dp_ratio);
 
 
 	/// Move the defender left.
 	/// Move the defender left.
 	void StartMove(float direction);	
 	void StartMove(float direction);	

+ 2 - 1
Samples/luainvaders/src/ElementGame.cpp

@@ -27,6 +27,7 @@
  */
  */
 
 
 #include "ElementGame.h"
 #include "ElementGame.h"
+#include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/ElementDocument.h>
 #include <RmlUi/Core/ElementDocument.h>
 #include <RmlUi/Core/Input.h>
 #include <RmlUi/Core/Input.h>
 #include <RmlUi/Core/Factory.h>
 #include <RmlUi/Core/Factory.h>
@@ -89,7 +90,7 @@ void ElementGame::OnUpdate()
 // Renders the game.
 // Renders the game.
 void ElementGame::OnRender()
 void ElementGame::OnRender()
 {
 {
-	game->Render();
+	game->Render(GetContext()->GetDensityIndependentPixelRatio());
 }
 }
 
 
 void ElementGame::OnChildAdd(Rml::Element* element)
 void ElementGame::OnChildAdd(Rml::Element* element)

+ 4 - 4
Samples/luainvaders/src/Game.cpp

@@ -140,7 +140,7 @@ void Game::Update()
 	}
 	}
 }
 }
 
 
-void Game::Render()
+void Game::Render(float dp_ratio)
 {	
 {	
 	if (defender_lives <= 0)
 	if (defender_lives <= 0)
 		return;
 		return;
@@ -148,7 +148,7 @@ void Game::Render()
 	// Render all available shields
 	// Render all available shields
 	for (int i = 0; i < NUM_SHIELDS; i++)
 	for (int i = 0; i < NUM_SHIELDS; i++)
 	{
 	{
-		shields[i]->Render();
+		shields[i]->Render(dp_ratio);
 	}
 	}
 
 
 	glEnable(GL_TEXTURE_2D);
 	glEnable(GL_TEXTURE_2D);
@@ -159,10 +159,10 @@ void Game::Render()
 	// Render all available invaders
 	// Render all available invaders
 	for (int i = 0; i < NUM_INVADERS + 1; i++)
 	for (int i = 0; i < NUM_INVADERS + 1; i++)
 	{
 	{
-		invaders[i]->Render();
+		invaders[i]->Render(dp_ratio);
 	}
 	}
 	
 	
-	defender->Render();
+	defender->Render(dp_ratio);
 
 
 	glEnd();
 	glEnd();
 }
 }

+ 1 - 1
Samples/luainvaders/src/Game.h

@@ -58,7 +58,7 @@ public:
 	void Update();
 	void Update();
 
 
 	/// Render the game
 	/// Render the game
-	void Render();
+	void Render(float dp_ratio);
 
 
 	/// Access the defender
 	/// Access the defender
 	Defender* GetDefender();
 	Defender* GetDefender();

+ 3 - 3
Samples/luainvaders/src/Invader.cpp

@@ -182,7 +182,7 @@ void Invader::UpdateAnimation()
 	}
 	}
 }
 }
 
 
-void Invader::Render()
+void Invader::Render(float dp_ratio)
 {
 {
 	if (type == MOTHERSHIP)
 	if (type == MOTHERSHIP)
 	{
 	{
@@ -192,11 +192,11 @@ void Invader::Render()
 	int sprite_offset = Rml::Math::RealToInteger((invader_sprites[sprite_index].dimensions.x - 48) / 2);
 	int sprite_offset = Rml::Math::RealToInteger((invader_sprites[sprite_index].dimensions.x - 48) / 2);
 
 
 	if (state != DEAD)
 	if (state != DEAD)
-		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y));
+		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y), dp_ratio);
 	
 	
 	if (bomb != NONE)
 	if (bomb != NONE)
 	{
 	{
-		bomb_sprites[bomb_animation_frame].Render(bomb_position);
+		bomb_sprites[bomb_animation_frame].Render(bomb_position, dp_ratio);
 	}
 	}
 
 
 	if (type == MOTHERSHIP)
 	if (type == MOTHERSHIP)

+ 1 - 1
Samples/luainvaders/src/Invader.h

@@ -60,7 +60,7 @@ public:
 	virtual void Update();	
 	virtual void Update();	
 
 
 	/// Render the invader
 	/// Render the invader
-	void Render();
+	void Render(float dp_ratio);
 
 
 	/// Update the invaders animation
 	/// Update the invaders animation
 	void UpdateAnimation();
 	void UpdateAnimation();

+ 6 - 3
Samples/luainvaders/src/Shield.cpp

@@ -119,11 +119,14 @@ const Rml::Vector2f& Shield::GetPosition() const
 	return position;
 	return position;
 }
 }
 
 
-void Shield::Render()
+void Shield::Render(float dp_ratio)
 {
 {
 	if (health > 0)
 	if (health > 0)
 	{
 	{
-		glPointSize((GLfloat) PIXEL_SIZE);
+		const Rml::Vector2f scaled_position = (dp_ratio * position).Round();
+		const int scaled_pixel = Rml::Math::RoundUpToInteger(PIXEL_SIZE * dp_ratio);
+
+		glPointSize((GLfloat)scaled_pixel);
 		glDisable(GL_TEXTURE_2D);
 		glDisable(GL_TEXTURE_2D);
 		glColor4ubv(GameDetails::GetDefenderColour());
 		glColor4ubv(GameDetails::GetDefenderColour());
 
 
@@ -135,7 +138,7 @@ void Shield::Render()
 			{
 			{
 				if (shield_cells[i][j] == ON)
 				if (shield_cells[i][j] == ON)
 				{
 				{
-					Rml::Vector2f cell_position = position + Rml::Vector2f((float) (PIXEL_SIZE * i), (float) (PIXEL_SIZE * j));
+					Rml::Vector2f cell_position = scaled_position + Rml::Vector2f(float(scaled_pixel * i), float(scaled_pixel * j));
 					glVertex2f(cell_position.x, cell_position.y);
 					glVertex2f(cell_position.x, cell_position.y);
 				}
 				}
 			}
 			}

+ 1 - 1
Samples/luainvaders/src/Shield.h

@@ -62,7 +62,7 @@ public:
 	const Rml::Vector2f& GetPosition() const;
 	const Rml::Vector2f& GetPosition() const;
 
 
 	/// Render the shield.
 	/// Render the shield.
-	void Render();
+	void Render(float dp_ratio);
 
 
 	/// Returns true if the position hits the shield
 	/// Returns true if the position hits the shield
 	/// If a hit is detected, will degrade the shield.
 	/// If a hit is detected, will degrade the shield.

+ 10 - 4
Samples/luainvaders/src/Sprite.cpp

@@ -27,6 +27,7 @@
  */
  */
 
 
 #include "Sprite.h"
 #include "Sprite.h"
+#include <RmlUi/Core/Math.h>
 #include <ShellOpenGL.h>
 #include <ShellOpenGL.h>
 
 
 Sprite::Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord) : dimensions(dimensions), top_left_texcoord(top_left_texcoord), bottom_right_texcoord(bottom_right_texcoord)
 Sprite::Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord) : dimensions(dimensions), top_left_texcoord(top_left_texcoord), bottom_right_texcoord(bottom_right_texcoord)
@@ -37,17 +38,22 @@ Sprite::~Sprite()
 {
 {
 }
 }
 
 
-void Sprite::Render(const Rml::Vector2f& position)
+void Sprite::Render(Rml::Vector2f position, const float dp_ratio)
 {
 {
+	position = (dp_ratio * position);
+	Rml::Vector2f dimensions_px = dp_ratio * dimensions;
+
+	Rml::Math::SnapToPixelGrid(position, dimensions_px);
+
 	glTexCoord2f(top_left_texcoord.x, top_left_texcoord.y);
 	glTexCoord2f(top_left_texcoord.x, top_left_texcoord.y);
 	glVertex2f(position.x, position.y);
 	glVertex2f(position.x, position.y);
 
 
 	glTexCoord2f(top_left_texcoord.x, bottom_right_texcoord.y);
 	glTexCoord2f(top_left_texcoord.x, bottom_right_texcoord.y);
-	glVertex2f(position.x, position.y + dimensions.y);
+	glVertex2f(position.x, position.y + dimensions_px.y);
 
 
 	glTexCoord2f(bottom_right_texcoord.x, bottom_right_texcoord.y);
 	glTexCoord2f(bottom_right_texcoord.x, bottom_right_texcoord.y);
-	glVertex2f(position.x + dimensions.x, position.y + dimensions.y);
+	glVertex2f(position.x + dimensions_px.x, position.y + dimensions_px.y);
 
 
 	glTexCoord2f(bottom_right_texcoord.x, top_left_texcoord.y);
 	glTexCoord2f(bottom_right_texcoord.x, top_left_texcoord.y);
-	glVertex2f(position.x + dimensions.x, position.y);
+	glVertex2f(position.x + dimensions_px.x, position.y);
 }
 }

+ 1 - 1
Samples/luainvaders/src/Sprite.h

@@ -41,7 +41,7 @@ public:
 	Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord);
 	Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord);
 	~Sprite();
 	~Sprite();
 
 
-	void Render(const Rml::Vector2f& position);
+	void Render(Rml::Vector2f position, float dp_ratio);
 
 
 	Rml::Vector2f dimensions;
 	Rml::Vector2f dimensions;
 	Rml::Vector2f top_left_texcoord;
 	Rml::Vector2f top_left_texcoord;

+ 1 - 1
Samples/luainvaders/src/main.cpp

@@ -103,7 +103,7 @@ int main(int, char**)
 
 
 	Rml::Debugger::Initialise(context);
 	Rml::Debugger::Initialise(context);
 	Input::SetContext(context);
 	Input::SetContext(context);
-	shell_renderer->SetContext(context);
+	Shell::SetContext(context);
 
 
 	// Load the font faces required for Invaders.
 	// Load the font faces required for Invaders.
 	Shell::LoadFonts("assets/");
 	Shell::LoadFonts("assets/");

+ 3 - 4
Samples/shell/include/Shell.h

@@ -90,12 +90,11 @@ public:
 	/// Get clipboard text.
 	/// Get clipboard text.
 	static void GetClipboardText(Rml::String& text);
 	static void GetClipboardText(Rml::String& text);
 	
 	
-	/// Sets the context to send window resized events to.
-	/// @param[in] context The context to send  events to.
+	/// Sets the RmlUi context to send window resized events to.
 	static void SetContext(Rml::Context* context);
 	static void SetContext(Rml::Context* context);
 
 
-private:
-	static Rml::Context* context;
+	/// Return the dp-ratio of the system.
+	static float GetDensityIndependentPixelRatio();
 };
 };
 
 
 #include "ShellSystemInterface.h"
 #include "ShellSystemInterface.h"

+ 2 - 7
Samples/shell/include/ShellRenderInterfaceExtensions.h

@@ -43,13 +43,8 @@ public:
      * @param[in] width width of viewport
      * @param[in] width width of viewport
      * @param[in] height height of viewport
      * @param[in] height height of viewport
 	 */
 	 */
-    virtual void SetViewport(int width, int height) = 0;
-	
-    /**
-	 * @param[in] context Rml::Context to set dimensions on when SetViewport is called
-     */
-    virtual void SetContext(void *context) = 0;
-	
+	virtual void SetViewport(int width, int height) = 0;
+
 	/// Attach the internal window buffer to a native window
 	/// Attach the internal window buffer to a native window
 	/// @param[in] nativeWindow A handle to the OS specific native window handle
 	/// @param[in] nativeWindow A handle to the OS specific native window handle
 	virtual bool AttachToNative(void *nativeWindow) = 0;
 	virtual bool AttachToNative(void *nativeWindow) = 0;

+ 0 - 2
Samples/shell/include/ShellRenderInterfaceOpenGL.h

@@ -79,7 +79,6 @@ public:
 
 
 	// ShellRenderInterfaceExtensions
 	// ShellRenderInterfaceExtensions
 	void SetViewport(int width, int height) override;
 	void SetViewport(int width, int height) override;
-	void SetContext(void *context) override;
 	bool AttachToNative(void *nativeWindow) override;
 	bool AttachToNative(void *nativeWindow) override;
 	void DetachFromNative(void) override;
 	void DetachFromNative(void) override;
 	void PrepareRenderBuffer(void) override;
 	void PrepareRenderBuffer(void) override;
@@ -89,7 +88,6 @@ protected:
 	int m_width;
 	int m_width;
 	int m_height;
 	int m_height;
 	bool m_transform_enabled;
 	bool m_transform_enabled;
-	void *m_rmlui_context;
 	
 	
 #if defined(RMLUI_PLATFORM_MACOSX)
 #if defined(RMLUI_PLATFORM_MACOSX)
 	AGLContext gl_context;
 	AGLContext gl_context;

+ 5 - 3
Samples/shell/include/win32/IncludeWindows.h

@@ -29,10 +29,12 @@
 #ifndef RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H
 #ifndef RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H
 #define RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H
 #define RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H
 
 
-#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0501
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
+#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0601
+	#undef _WIN32_WINNT
+	// Target Windows 7
+	#define _WIN32_WINNT 0x0601
 #endif
 #endif
+
 #define UNICODE
 #define UNICODE
 #define _UNICODE
 #define _UNICODE
 #define WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN

+ 1 - 1
Samples/shell/src/ShellRenderInterfaceOpenGL.cpp

@@ -35,7 +35,7 @@
 
 
 #define GL_CLAMP_TO_EDGE 0x812F
 #define GL_CLAMP_TO_EDGE 0x812F
 
 
-ShellRenderInterfaceOpenGL::ShellRenderInterfaceOpenGL() : m_width(0), m_height(0), m_transform_enabled(false), m_rmlui_context(nullptr)
+ShellRenderInterfaceOpenGL::ShellRenderInterfaceOpenGL() : m_width(0), m_height(0), m_transform_enabled(false)
 {
 {
 
 
 }
 }

+ 27 - 6
Samples/shell/src/macosx/ShellMacOSX.cpp

@@ -53,15 +53,31 @@ static const EventTypeSpec WINDOW_EVENTS[] = {
 	{ kEventClassWindow, kEventWindowBoundsChanged },
 	{ kEventClassWindow, kEventWindowBoundsChanged },
 };
 };
 
 
+static Rml::Context* context = nullptr;
+static ShellRenderInterfaceExtensions* shell_renderer;
+static UniquePtr<ShellFileInterface> file_interface;
+
 static WindowRef window;
 static WindowRef window;
 static timeval start_time;
 static timeval start_time;
 static Rml::String clipboard_text;
 static Rml::String clipboard_text;
-
-static Rml::UniquePtr<ShellFileInterface> file_interface;
+static int window_width = 0;
+static int window_height = 0;
 
 
 static void IdleTimerCallback(EventLoopTimerRef timer, EventLoopIdleTimerMessage inState, void* p);
 static void IdleTimerCallback(EventLoopTimerRef timer, EventLoopIdleTimerMessage inState, void* p);
 static OSStatus EventHandler(EventHandlerCallRef next_handler, EventRef event, void* p);
 static OSStatus EventHandler(EventHandlerCallRef next_handler, EventRef event, void* p);
 
 
+static void UpdateWindowDimensions(int width = 0, int height = 0)
+{
+	if (width > 0)
+		window_width = width;
+	if (height > 0)
+		window_height = height;
+	if (context)
+		context->SetDimensions(Rml::Vector2i(window_width, window_height));
+	if (shell_renderer)
+		shell_renderer->SetViewport(window_width, window_height);
+}
+
 bool Shell::Initialise()
 bool Shell::Initialise()
 {
 {
 	gettimeofday(&start_time, nullptr);
 	gettimeofday(&start_time, nullptr);
@@ -104,12 +120,12 @@ Rml::String Shell::FindSamplesRoot()
 	return (executable_path + "../../../" + path);
 	return (executable_path + "../../../" + path);
 }
 }
 
 
-static ShellRenderInterfaceExtensions *shell_renderer;
-
 bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize)
 bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize)
 {
 {
 	shell_renderer = _shell_renderer;
 	shell_renderer = _shell_renderer;
 	Rect content_bounds = { 60, 20, 60 + height, 20 + width };
 	Rect content_bounds = { 60, 20, 60 + height, 20 + width };
+	window_width = width;
+	window_height = height;
 
 
 	OSStatus result = CreateNewWindow(kDocumentWindowClass,
 	OSStatus result = CreateNewWindow(kDocumentWindowClass,
 									  (allow_resize ? (kWindowStandardDocumentAttributes | kWindowLiveResizeAttribute) :
 									  (allow_resize ? (kWindowStandardDocumentAttributes | kWindowLiveResizeAttribute) :
@@ -257,7 +273,6 @@ void Shell::SetMouseCursor(const Rml::String& cursor_name)
 	// Not implemented
 	// Not implemented
 }
 }
 
 
-
 void Shell::SetClipboardText(const Rml::String& text)
 void Shell::SetClipboardText(const Rml::String& text)
 {
 {
 	// Todo: interface with system clipboard
 	// Todo: interface with system clipboard
@@ -270,6 +285,12 @@ void Shell::GetClipboardText(Rml::String& text)
 	text = clipboard_text;
 	text = clipboard_text;
 }
 }
 
 
+void Shell::SetContext(Rml::Context* new_context)
+{
+	context = new_context;
+	UpdateWindowDimensions();
+}
+
 static void IdleTimerCallback(EventLoopTimerRef timer, EventLoopIdleTimerMessage inState, void* p)
 static void IdleTimerCallback(EventLoopTimerRef timer, EventLoopIdleTimerMessage inState, void* p)
 {
 {
 	Shell::ShellIdleFunction function = (Shell::ShellIdleFunction) p;
 	Shell::ShellIdleFunction function = (Shell::ShellIdleFunction) p;
@@ -300,7 +321,7 @@ static OSStatus EventHandler(EventHandlerCallRef next_handler, EventRef event, v
 						UInt32 width = bounds.right - bounds.left;
 						UInt32 width = bounds.right - bounds.left;
 						UInt32 height = bounds.bottom - bounds.top;
 						UInt32 height = bounds.bottom - bounds.top;
 
 
-						shell_renderer->SetViewport(width, height);
+						UpdateWindowDimensions((int)width, (int)height);
 					}
 					}
 					break;
 					break;
 			}
 			}

+ 0 - 11
Samples/shell/src/macosx/ShellRenderInterfaceExtensionsOpenGL_MacOSX.cpp

@@ -29,15 +29,9 @@
 #include <ShellRenderInterfaceExtensions.h>
 #include <ShellRenderInterfaceExtensions.h>
 #include <ShellRenderInterfaceOpenGL.h>
 #include <ShellRenderInterfaceOpenGL.h>
 #include <Carbon/Carbon.h>
 #include <Carbon/Carbon.h>
-#include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Platform.h>
 #include <RmlUi/Core/Platform.h>
 #include <RmlUi/Core/Types.h>
 #include <RmlUi/Core/Types.h>
 
 
-void ShellRenderInterfaceOpenGL::SetContext(void *context)
-{
-	m_rmlui_context = context;
-}
-
 void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 {
 {
 	if(m_width != width || m_height != height) {
 	if(m_width != width || m_height != height) {
@@ -55,11 +49,6 @@ void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 		glLoadMatrixf(view);
 		glLoadMatrixf(view);
 
 
 		aglUpdateContext(gl_context);
 		aglUpdateContext(gl_context);
-
-		if(m_rmlui_context != nullptr)
-		{
-			((Rml::Context*)m_rmlui_context)->SetDimensions(Rml::Vector2i(width, height));
-		}
 	}
 	}
 }
 }
 
 

+ 20 - 4
Samples/shell/src/win32/InputWin32.cpp

@@ -29,6 +29,7 @@
 #include <win32/InputWin32.h>
 #include <win32/InputWin32.h>
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Input.h>
 #include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/Math.h>
 #include <RmlUi/Core/StringUtilities.h>
 #include <RmlUi/Core/StringUtilities.h>
 #include <RmlUi/Debugger.h>
 #include <RmlUi/Debugger.h>
 #include <Shell.h>
 #include <Shell.h>
@@ -97,14 +98,29 @@ void InputWin32::ProcessWindowsEvent(HWND window, UINT message, WPARAM w_param,
 			Rml::Input::KeyIdentifier key_identifier = key_identifier_map[w_param];
 			Rml::Input::KeyIdentifier key_identifier = key_identifier_map[w_param];
 			int key_modifier_state = GetKeyModifierState();
 			int key_modifier_state = GetKeyModifierState();
 
 
-			// Check for F8 to toggle the debugger.
+			// Toggle debugger and set 'dp'-ratio ctrl +/-/0 keys
 			if (key_identifier == Rml::Input::KI_F8)
 			if (key_identifier == Rml::Input::KI_F8)
 			{
 			{
 				Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible());
 				Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible());
-				break;
 			}
 			}
-
-			context->ProcessKeyDown(key_identifier, key_modifier_state);
+			else if (key_identifier == Rml::Input::KI_0 && key_modifier_state & Rml::Input::KM_CTRL)
+			{
+				context->SetDensityIndependentPixelRatio(key_modifier_state == Rml::Input::KM_SHIFT ? 1.f : Shell::GetDensityIndependentPixelRatio());
+			}
+			else if (key_identifier == Rml::Input::KI_OEM_MINUS && key_modifier_state & Rml::Input::KM_CTRL)
+			{
+				const float new_dp_ratio = Rml::Math::Max(context->GetDensityIndependentPixelRatio() / 1.2f, 0.5f);
+				context->SetDensityIndependentPixelRatio(new_dp_ratio);
+			}
+			else if (key_identifier == Rml::Input::KI_OEM_PLUS && key_modifier_state & Rml::Input::KM_CTRL)
+			{
+				const float new_dp_ratio = Rml::Math::Min(context->GetDensityIndependentPixelRatio() * 1.2f, 2.5f);
+				context->SetDensityIndependentPixelRatio(new_dp_ratio);
+			}
+			else
+			{
+				context->ProcessKeyDown(key_identifier, key_modifier_state);
+			}
 		}
 		}
 		break;
 		break;
 
 

+ 0 - 10
Samples/shell/src/win32/ShellRenderInterfaceExtensionsOpenGL_Win32.cpp

@@ -29,17 +29,12 @@
 #include <ShellRenderInterfaceExtensions.h>
 #include <ShellRenderInterfaceExtensions.h>
 #include <ShellRenderInterfaceOpenGL.h>
 #include <ShellRenderInterfaceOpenGL.h>
 #include <win32/IncludeWindows.h>
 #include <win32/IncludeWindows.h>
-#include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Platform.h>
 #include <RmlUi/Core/Platform.h>
 #include <RmlUi/Core/Profiling.h>
 #include <RmlUi/Core/Profiling.h>
 #include <RmlUi/Core/Types.h>
 #include <RmlUi/Core/Types.h>
 #include <Shell.h>
 #include <Shell.h>
 #include <string.h>
 #include <string.h>
 
 
-void ShellRenderInterfaceOpenGL::SetContext(void *context)
-{
-	m_rmlui_context = context;
-}
 
 
 void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 {
 {
@@ -56,11 +51,6 @@ void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 		view = Rml::Matrix4f::Identity();
 		view = Rml::Matrix4f::Identity();
 		glMatrixMode(GL_MODELVIEW);
 		glMatrixMode(GL_MODELVIEW);
 		glLoadMatrixf(view.data());
 		glLoadMatrixf(view.data());
-
-		if(m_rmlui_context != nullptr)
-		{
-			((Rml::Context*)m_rmlui_context)->SetDimensions(Rml::Vector2i(width, height));
-		}
 	}
 	}
 }
 }
 
 

+ 119 - 6
Samples/shell/src/win32/ShellWin32.cpp

@@ -37,12 +37,20 @@
 
 
 static LRESULT CALLBACK WindowProcedure(HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param);
 static LRESULT CALLBACK WindowProcedure(HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param);
 
 
+static Rml::Context* context = nullptr;
+static ShellRenderInterfaceExtensions* shell_renderer = nullptr;
+
 static bool activated = true;
 static bool activated = true;
 static bool running = false;
 static bool running = false;
 static Rml::U16String instance_name;
 static Rml::U16String instance_name;
 static HWND window_handle = nullptr;
 static HWND window_handle = nullptr;
 static HINSTANCE instance_handle = nullptr;
 static HINSTANCE instance_handle = nullptr;
 
 
+static bool has_dpi_support = false;
+static UINT window_dpi = USER_DEFAULT_SCREEN_DPI;
+static int window_width = 0;
+static int window_height = 0;
+
 static double time_frequency;
 static double time_frequency;
 static LARGE_INTEGER time_startup;
 static LARGE_INTEGER time_startup;
 
 
@@ -57,6 +65,49 @@ static HCURSOR cursor_text = nullptr;
 static HCURSOR cursor_unavailable = nullptr;
 static HCURSOR cursor_unavailable = nullptr;
 
 
 
 
+#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
+#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4)
+#endif
+#ifndef WM_DPICHANGED
+#define WM_DPICHANGED 0x02E0
+#endif
+
+// Declare pointers to the DPI aware Windows API functions.
+using ProcSetProcessDpiAwarenessContext = BOOL(WINAPI*)(HANDLE value);
+using ProcGetDpiForWindow = UINT(WINAPI*)(HWND hwnd);
+using ProcAdjustWindowRectExForDpi = BOOL(WINAPI*)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
+
+static ProcSetProcessDpiAwarenessContext procSetProcessDpiAwarenessContext = NULL;
+static ProcGetDpiForWindow procGetDpiForWindow = NULL;
+static ProcAdjustWindowRectExForDpi procAdjustWindowRectExForDpi = NULL;
+
+
+static void UpdateDpi()
+{
+	if (has_dpi_support)
+	{
+		UINT dpi = procGetDpiForWindow(window_handle);
+		if (dpi != 0)
+		{
+			window_dpi = dpi;
+			if (context)
+				context->SetDensityIndependentPixelRatio(Shell::GetDensityIndependentPixelRatio());
+		}
+	}
+}
+
+static void UpdateWindowDimensions(int width = 0, int height = 0)
+{
+	if (width > 0)
+		window_width = width;
+	if (height > 0)
+		window_height = height;
+	if (context)
+		context->SetDimensions(Rml::Vector2i(window_width, window_height));
+	if (shell_renderer)
+		shell_renderer->SetViewport(window_width, window_height);
+}
+
 bool Shell::Initialise()
 bool Shell::Initialise()
 {
 {
 	instance_handle = GetModuleHandle(nullptr);
 	instance_handle = GetModuleHandle(nullptr);
@@ -83,6 +134,23 @@ bool Shell::Initialise()
 	file_interface = Rml::MakeUnique<ShellFileInterface>(root);
 	file_interface = Rml::MakeUnique<ShellFileInterface>(root);
 	Rml::SetFileInterface(file_interface.get());
 	Rml::SetFileInterface(file_interface.get());
 
 
+	// See if we have Per Monitor V2 DPI awareness. Requires Windows 10, version 1703.
+	// Cast function pointers to void* first for MinGW not to emit errors.
+	procSetProcessDpiAwarenessContext = (ProcSetProcessDpiAwarenessContext)(void*)GetProcAddress(
+		GetModuleHandle(TEXT("User32.dll")),
+		"SetProcessDpiAwarenessContext"
+	);
+	procGetDpiForWindow = (ProcGetDpiForWindow)(void*)GetProcAddress(
+		GetModuleHandle(TEXT("User32.dll")),
+		"GetDpiForWindow"
+	);
+	procAdjustWindowRectExForDpi = (ProcAdjustWindowRectExForDpi)(void*)GetProcAddress(
+		GetModuleHandle(TEXT("User32.dll")),
+		"AdjustWindowRectExForDpi"
+	);
+
+	has_dpi_support = (procSetProcessDpiAwarenessContext != NULL && procGetDpiForWindow != NULL && procAdjustWindowRectExForDpi != NULL);
+
 	return result;
 	return result;
 }
 }
 
 
@@ -128,9 +196,15 @@ Rml::String Shell::FindSamplesRoot()
 	return Rml::String();
 	return Rml::String();
 }
 }
 
 
-static ShellRenderInterfaceExtensions *shell_renderer = nullptr;
+
 bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize)
 bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize)
 {
 {
+	// Activate Per Monitor V2.
+	if (has_dpi_support && !procSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
+	{
+		has_dpi_support = false;
+	}
+
 	WNDCLASSW window_class;
 	WNDCLASSW window_class;
 
 
 	Rml::U16String name = Rml::StringUtilities::ToUTF16(Rml::String(in_name));
 	Rml::U16String name = Rml::StringUtilities::ToUTF16(Rml::String(in_name));
@@ -160,7 +234,7 @@ bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_she
 								   (LPCWSTR)name.data(),
 								   (LPCWSTR)name.data(),
 								   WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
 								   WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
 								   0, 0,	// Window position.
 								   0, 0,	// Window position.
-								   width, height,// Window size.
+								   0, 0,// Window size.
 								   nullptr,
 								   nullptr,
 								   nullptr,
 								   nullptr,
 								   instance_handle,
 								   instance_handle,
@@ -173,6 +247,13 @@ bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_she
 		return false;
 		return false;
 	}
 	}
 
 
+	window_width = width;
+	window_height = height;
+
+	UpdateDpi();
+	window_width = (width * window_dpi) / USER_DEFAULT_SCREEN_DPI;
+	window_height = (height * window_dpi) / USER_DEFAULT_SCREEN_DPI;
+
 	instance_name = name;
 	instance_name = name;
 
 
 	DWORD style = (allow_resize ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX));
 	DWORD style = (allow_resize ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX));
@@ -182,9 +263,12 @@ bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_she
 	RECT window_rect;
 	RECT window_rect;
 	window_rect.top = 0;
 	window_rect.top = 0;
 	window_rect.left = 0;
 	window_rect.left = 0;
-	window_rect.right = width;
-	window_rect.bottom = height;
-	AdjustWindowRectEx(&window_rect, style, FALSE, extended_style);
+	window_rect.right = window_width;
+	window_rect.bottom = window_height;
+	if (has_dpi_support)
+		procAdjustWindowRectExForDpi(&window_rect, style, FALSE, extended_style, window_dpi);
+	else
+		AdjustWindowRectEx(&window_rect, style, FALSE, extended_style);
 
 
 	SetWindowLong(window_handle, GWL_EXSTYLE, extended_style);
 	SetWindowLong(window_handle, GWL_EXSTYLE, extended_style);
 	SetWindowLong(window_handle, GWL_STYLE, style);
 	SetWindowLong(window_handle, GWL_STYLE, style);
@@ -199,6 +283,8 @@ bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_she
 		}
 		}
 	}
 	}
 
 
+	UpdateWindowDimensions();
+
 	// Resize the window.
 	// Resize the window.
 	SetWindowPos(window_handle, HWND_TOP, 0, 0, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, SWP_NOACTIVATE);
 	SetWindowPos(window_handle, HWND_TOP, 0, 0, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, SWP_NOACTIVATE);
 
 
@@ -376,6 +462,18 @@ void Shell::GetClipboardText(Rml::String& text)
 	}
 	}
 }
 }
 
 
+void Shell::SetContext(Rml::Context* new_context)
+{
+	context = new_context;
+	UpdateDpi();
+	UpdateWindowDimensions();
+}
+
+float Shell::GetDensityIndependentPixelRatio()
+{
+	return float(window_dpi) / float(USER_DEFAULT_SCREEN_DPI);
+}
+
 static LRESULT CALLBACK WindowProcedure(HWND local_window_handle, UINT message, WPARAM w_param, LPARAM l_param)
 static LRESULT CALLBACK WindowProcedure(HWND local_window_handle, UINT message, WPARAM w_param, LPARAM l_param)
 {
 {
 	// See what kind of message we've got.
 	// See what kind of message we've got.
@@ -406,7 +504,22 @@ static LRESULT CALLBACK WindowProcedure(HWND local_window_handle, UINT message,
 		{
 		{
 			int width = LOWORD(l_param);
 			int width = LOWORD(l_param);
 			int height = HIWORD(l_param);
 			int height = HIWORD(l_param);
-			shell_renderer->SetViewport(width, height);
+			UpdateWindowDimensions(width, height);
+		}
+		break;
+
+		case WM_DPICHANGED:
+		{
+			UpdateDpi();
+
+			RECT* const new_pos = (RECT*)l_param;
+			SetWindowPos(window_handle,
+				NULL,
+				new_pos->left,
+				new_pos->top,
+				new_pos->right - new_pos->left,
+				new_pos->bottom - new_pos->top,
+				SWP_NOZORDER | SWP_NOACTIVATE);
 		}
 		}
 		break;
 		break;
 
 

+ 0 - 11
Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp

@@ -30,16 +30,10 @@
 #include <ShellRenderInterfaceOpenGL.h>
 #include <ShellRenderInterfaceOpenGL.h>
 #include <X11/Xlib.h>
 #include <X11/Xlib.h>
 #include <X11/extensions/xf86vmode.h>
 #include <X11/extensions/xf86vmode.h>
-#include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Platform.h>
 #include <RmlUi/Core/Platform.h>
 #include <RmlUi/Core/Types.h>
 #include <RmlUi/Core/Types.h>
 #include "../../include/Shell.h"
 #include "../../include/Shell.h"
 
 
-void ShellRenderInterfaceOpenGL::SetContext(void *context)
-{
-	m_rmlui_context = context;
-}
-
 
 
 void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 {
 {
@@ -56,11 +50,6 @@ void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 		view = Rml::Matrix4f::Identity();
 		view = Rml::Matrix4f::Identity();
 		glMatrixMode(GL_MODELVIEW);
 		glMatrixMode(GL_MODELVIEW);
 		glLoadMatrixf(view.data());
 		glLoadMatrixf(view.data());
-
-		if(m_rmlui_context != nullptr)
-		{
-			((Rml::Context*)m_rmlui_context)->SetDimensions(Rml::Vector2i(width, height));
-		}
 	}
 	}
 }
 }
 
 

+ 34 - 8
Samples/shell/src/x11/ShellX11.cpp

@@ -28,7 +28,9 @@
 
 
 #include <Shell.h>
 #include <Shell.h>
 #include <ShellOpenGL.h>
 #include <ShellOpenGL.h>
-#include <RmlUi/Core.h>
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Types.h>
 #include "ShellFileInterface.h"
 #include "ShellFileInterface.h"
 #include <x11/InputX11.h>
 #include <x11/InputX11.h>
 #include <X11/Xlib.h>
 #include <X11/Xlib.h>
@@ -45,13 +47,22 @@
 #include <stdarg.h>
 #include <stdarg.h>
 #include <string.h>
 #include <string.h>
 
 
+static Rml::Context* context = nullptr;
+static ShellRenderInterfaceExtensions* shell_renderer = nullptr;
+
 static bool running = false;
 static bool running = false;
 static int screen = -1;
 static int screen = -1;
 static timeval start_time;
 static timeval start_time;
 static Rml::String clipboard_text;
 static Rml::String clipboard_text;
+static int window_width = 0;
+static int window_height = 0;
 
 
 static Rml::UniquePtr<ShellFileInterface> file_interface;
 static Rml::UniquePtr<ShellFileInterface> file_interface;
 
 
+static Display* display = nullptr;
+static XVisualInfo* visual_info = nullptr;
+static Window window = 0;
+
 static Cursor cursor_default = 0;
 static Cursor cursor_default = 0;
 static Cursor cursor_move = 0;
 static Cursor cursor_move = 0;
 static Cursor cursor_pointer = 0;
 static Cursor cursor_pointer = 0;
@@ -60,6 +71,18 @@ static Cursor cursor_cross = 0;
 static Cursor cursor_text = 0;
 static Cursor cursor_text = 0;
 static Cursor cursor_unavailable = 0;
 static Cursor cursor_unavailable = 0;
 
 
+static void UpdateWindowDimensions(int width = 0, int height = 0)
+{
+	if (width > 0)
+		window_width = width;
+	if (height > 0)
+		window_height = height;
+	if (context)
+		context->SetDimensions(Rml::Vector2i(window_width, window_height));
+	if (shell_renderer)
+		shell_renderer->SetViewport(window_width, window_height);
+}
+
 static bool isRegularFile(const Rml::String& path)
 static bool isRegularFile(const Rml::String& path)
 {
 {
 	struct stat sb;
 	struct stat sb;
@@ -126,18 +149,15 @@ Rml::String Shell::FindSamplesRoot()
 	return Rml::String();
 	return Rml::String();
 }
 }
 
 
-static Display* display = nullptr;
-static XVisualInfo* visual_info = nullptr;
-static Window window = 0;
-
-static ShellRenderInterfaceExtensions *shell_renderer = nullptr;
-
 bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize)
 bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize)
 {
 {
 	display = XOpenDisplay(0);
 	display = XOpenDisplay(0);
 	if (display == nullptr)
 	if (display == nullptr)
 		return false;
 		return false;
 
 
+	window_width = width;
+	window_height = height;
+
 	// This initialise they keyboard to keycode mapping system of X11
 	// This initialise they keyboard to keycode mapping system of X11
 	// itself.  It must be done here as it needs to query the connected
 	// itself.  It must be done here as it needs to query the connected
 	// X server display for information about its install keymap abilities.
 	// X server display for information about its install keymap abilities.
@@ -300,7 +320,7 @@ void Shell::EventLoop(ShellIdleFunction idle_function)
 					int x = event.xconfigure.width;
 					int x = event.xconfigure.width;
 					int y = event.xconfigure.height;
 					int y = event.xconfigure.height;
 
 
-					shell_renderer->SetViewport(x, y);
+					UpdateWindowDimensions(x, y);
 				}
 				}
 				break;
 				break;
 				
 				
@@ -412,3 +432,9 @@ void Shell::GetClipboardText(Rml::String& text)
 	// Todo: interface with system clipboard
 	// Todo: interface with system clipboard
 	text = clipboard_text;
 	text = clipboard_text;
 }
 }
+
+void Shell::SetContext(Rml::Context* new_context)
+{
+	context = new_context;
+	UpdateWindowDimensions();
+}

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

@@ -44,13 +44,13 @@ body
 	font-family: LatoLatin;
 	font-family: LatoLatin;
 	font-weight: normal;
 	font-weight: normal;
 	font-style: normal;
 	font-style: normal;
-	font-size: 15px;
+	font-size: 15dp;
 	color: white;
 	color: white;
 }
 }
 
 
 body.window
 body.window
 {
 {
-	padding: 10px 15px;
+	padding: 10dp 15dp;
 	
 	
 	decorator: tiled-box(
 	decorator: tiled-box(
 		window-tl, window-t, window-tr, 
 		window-tl, window-t, window-tr, 
@@ -61,20 +61,20 @@ body.window
 div#title-bar
 div#title-bar
 {
 {
 	position: absolute;
 	position: absolute;
-	top: -40px;
+	top: -40dp;
 }
 }
 
 
 div#title-bar span
 div#title-bar span
 {
 {
-	padding-left: 85px;
-	padding-right: 25px;
-	padding-top: 17px;
-	padding-bottom: 48px;
+	padding-left: 85dp;
+	padding-right: 25dp;
+	padding-top: 17dp;
+	padding-bottom: 48dp;
 
 
-	font-size: 20px;
+	font-size: 20dp;
 	font-weight: bold;
 	font-weight: bold;
 
 
-	font-effect: glow(2px 2px 0px 1px #1117);
+	font-effect: glow(2dp 2dp 0dp 1dp #1117);
 	
 	
 	decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
 	decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
 }
 }
@@ -89,10 +89,10 @@ div#content
 
 
 scrollbarvertical
 scrollbarvertical
 {
 {
-	margin-top: -6px;
-	margin-bottom: -6px;
-	margin-right: -11px;
-	width: 27px;
+	margin-top: -6dp;
+	margin-bottom: -6dp;
+	margin-right: -11dp;
+	width: 27dp;
 }
 }
 
 
 scrollbarvertical slidertrack
 scrollbarvertical slidertrack
@@ -106,9 +106,9 @@ scrollbarvertical slidertrack:active
 
 
 scrollbarvertical sliderbar
 scrollbarvertical sliderbar
 {
 {
-	margin-left: 4px;
-	width: 23px;
-	min-height: 46px;
+	margin-left: 4dp;
+	width: 23dp;
+	min-height: 46dp;
 
 
 	decorator: tiled-vertical( sliderbar-t, sliderbar-c, sliderbar-b );
 	decorator: tiled-vertical( sliderbar-t, sliderbar-c, sliderbar-b );
 }
 }
@@ -126,8 +126,8 @@ scrollbarvertical sliderbar:active
 scrollbarvertical sliderarrowdec,
 scrollbarvertical sliderarrowdec,
 scrollbarvertical sliderarrowinc
 scrollbarvertical sliderarrowinc
 {
 {
-	width: 27px;
-	height: 24px;
+	width: 27dp;
+	height: 24dp;
 }
 }
 
 
 scrollbarvertical sliderarrowdec
 scrollbarvertical sliderarrowdec

+ 4 - 4
Samples/tutorial/datagrid/data/tutorial.rml

@@ -5,8 +5,8 @@
 	<style>
 	<style>
 		body
 		body
 		{
 		{
-			width: 400px;
-			height: 300px;
+			width: 400dp;
+			height: 300dp;
 
 
 			margin: auto;
 			margin: auto;
 		}
 		}
@@ -14,8 +14,8 @@
 		defender
 		defender
 		{
 		{
 				display: block;
 				display: block;
-				width: 64px;
-				height: 16px;
+				width: 64dp;
+				height: 16dp;
 
 
 				decorator: defender( ../../../assets/high_scores_defender.tga );
 				decorator: defender( ../../../assets/high_scores_defender.tga );
 		}
 		}

+ 2 - 2
Samples/tutorial/datagrid/src/DecoratorDefender.cpp

@@ -19,9 +19,9 @@ DecoratorDefender::~DecoratorDefender()
 {
 {
 }
 }
 
 
-bool DecoratorDefender::Initialise(const Rml::String& image_source, const Rml::String& image_path)
+bool DecoratorDefender::Initialise(const Rml::Texture& texture)
 {
 {
-	image_index = LoadTexture(image_source, image_path);
+	image_index = AddTexture(texture);
 	if (image_index == -1)
 	if (image_index == -1)
 	{
 	{
 		return false;
 		return false;

Some files were not shown because too many files changed in this diff