Forráskód Böngészése

Merge branch 'text' into develop

Michael Ragazzon 6 éve
szülő
commit
f49f5bc83e
100 módosított fájl, 3560 hozzáadás és 2710 törlés
  1. 28 38
      CMake/FileList.cmake
  2. 4 0
      CMake/SampleFileList.cmake
  3. 23 3
      CMake/gen_filelists.sh
  4. 4 1
      CMakeLists.txt
  5. 0 1
      Include/RmlUi/Core/ComputedValues.h
  6. 6 4
      Include/RmlUi/Core/Context.h
  7. 21 3
      Include/RmlUi/Core/Core.h
  8. 4 4
      Include/RmlUi/Core/ElementText.h
  9. 1 5
      Include/RmlUi/Core/ElementUtilities.h
  10. 52 40
      Include/RmlUi/Core/FontEngineInterface.h
  11. 20 10
      Include/RmlUi/Core/FontGlyph.h
  12. 0 1
      Include/RmlUi/Core/ID.h
  13. 115 14
      Include/RmlUi/Core/StringUtilities.h
  14. 2 2
      Include/RmlUi/Core/SystemInterface.h
  15. 22 4
      Include/RmlUi/Core/Texture.h
  16. 2 2
      Include/RmlUi/Core/TypeConverter.inl
  17. 8 11
      Include/RmlUi/Core/Types.h
  18. 1 1
      Include/RmlUi/Core/Variant.h
  19. 1 1
      Include/RmlUi/Core/Variant.inl
  20. 0 270
      Samples/assets/Arial.fnt
  21. BIN
      Samples/assets/Arial_0.tga
  22. 97 0
      Samples/assets/LICENSE.txt
  23. BIN
      Samples/assets/NotoEmoji-Regular.ttf
  24. 0 28
      Samples/assets/bitmapfont.rml
  25. 758 0
      Samples/basic/bitmapfont/data/Comfortaa_Regular_22.fnt
  26. BIN
      Samples/basic/bitmapfont/data/Comfortaa_Regular_22.tga
  27. 49 0
      Samples/basic/bitmapfont/data/LICENSE.txt
  28. 31 0
      Samples/basic/bitmapfont/data/bitmapfont.rml
  29. 314 0
      Samples/basic/bitmapfont/src/FontEngineBitmap.cpp
  30. 133 0
      Samples/basic/bitmapfont/src/FontEngineBitmap.h
  31. 117 0
      Samples/basic/bitmapfont/src/FontEngineInterfaceBitmap.cpp
  32. 99 0
      Samples/basic/bitmapfont/src/FontEngineInterfaceBitmap.h
  33. 29 4
      Samples/basic/bitmapfont/src/main.cpp
  34. 19 14
      Samples/basic/demo/data/demo.rml
  35. 4 4
      Samples/basic/sdl2/src/main.cpp
  36. 4 4
      Samples/basic/sfml2/src/main.cpp
  37. 1 1
      Samples/shell/include/Input.h
  38. 2 2
      Samples/shell/include/Shell.h
  39. 2 2
      Samples/shell/include/ShellSystemInterface.h
  40. 4 3
      Samples/shell/include/win32/InputWin32.h
  41. 11 9
      Samples/shell/src/Input.cpp
  42. 5 2
      Samples/shell/src/Shell.cpp
  43. 2 2
      Samples/shell/src/ShellSystemInterface.cpp
  44. 2 2
      Samples/shell/src/macosx/InputMacOSX.cpp
  45. 3 3
      Samples/shell/src/macosx/ShellMacOSX.cpp
  46. 34 7
      Samples/shell/src/win32/InputWin32.cpp
  47. 26 23
      Samples/shell/src/win32/ShellWin32.cpp
  48. 2 2
      Samples/shell/src/x11/InputX11.cpp
  49. 3 3
      Samples/shell/src/x11/ShellX11.cpp
  50. 1 1
      Source/Controls/ElementFormControlTextArea.cpp
  51. 1 1
      Source/Controls/InputTypeText.cpp
  52. 175 78
      Source/Controls/WidgetTextInput.cpp
  53. 17 8
      Source/Controls/WidgetTextInput.h
  54. 1 1
      Source/Controls/WidgetTextInputMultiLine.cpp
  55. 1 1
      Source/Controls/WidgetTextInputMultiLine.h
  56. 1 1
      Source/Controls/WidgetTextInputSingleLine.cpp
  57. 1 1
      Source/Controls/WidgetTextInputSingleLine.h
  58. 1 1
      Source/Controls/WidgetTextInputSingleLinePassword.cpp
  59. 0 153
      Source/Core/BitmapFont/BitmapFontDefinitions.h
  60. 0 129
      Source/Core/BitmapFont/FontFace.cpp
  61. 0 73
      Source/Core/BitmapFont/FontFace.h
  62. 0 185
      Source/Core/BitmapFont/FontFaceHandle.cpp
  63. 0 98
      Source/Core/BitmapFont/FontFaceHandle.h
  64. 0 131
      Source/Core/BitmapFont/FontFaceLayer.cpp
  65. 0 82
      Source/Core/BitmapFont/FontFaceLayer.h
  66. 0 59
      Source/Core/BitmapFont/FontFamily.cpp
  67. 0 69
      Source/Core/BitmapFont/FontFamily.h
  68. 0 121
      Source/Core/BitmapFont/FontParser.cpp
  69. 0 72
      Source/Core/BitmapFont/FontParser.h
  70. 0 174
      Source/Core/BitmapFont/FontProvider.cpp
  71. 0 85
      Source/Core/BitmapFont/FontProvider.h
  72. 6 1
      Source/Core/Context.cpp
  73. 15 2
      Source/Core/Core.cpp
  74. 1 2
      Source/Core/Decorator.cpp
  75. 2 1
      Source/Core/DecoratorTiledInstancer.cpp
  76. 0 1
      Source/Core/Element.cpp
  77. 1 1
      Source/Core/ElementDocument.cpp
  78. 1 5
      Source/Core/ElementImage.cpp
  79. 4 7
      Source/Core/ElementStyle.cpp
  80. 54 50
      Source/Core/ElementTextDefault.cpp
  81. 14 17
      Source/Core/ElementTextDefault.h
  82. 1 15
      Source/Core/ElementUtilities.cpp
  83. 1 1
      Source/Core/Factory.cpp
  84. 0 149
      Source/Core/FontDatabaseDefault.cpp
  85. 28 28
      Source/Core/FontEngineDefault/FontEngineInterfaceDefault.cpp
  86. 82 0
      Source/Core/FontEngineDefault/FontEngineInterfaceDefault.h
  87. 39 3
      Source/Core/FontEngineDefault/FontFace.cpp
  88. 12 18
      Source/Core/FontEngineDefault/FontFace.h
  89. 185 79
      Source/Core/FontEngineDefault/FontFaceHandleDefault.cpp
  90. 50 70
      Source/Core/FontEngineDefault/FontFaceHandleDefault.h
  91. 82 65
      Source/Core/FontEngineDefault/FontFaceLayer.cpp
  92. 36 42
      Source/Core/FontEngineDefault/FontFaceLayer.h
  93. 16 10
      Source/Core/FontEngineDefault/FontFamily.cpp
  94. 12 13
      Source/Core/FontEngineDefault/FontFamily.h
  95. 195 0
      Source/Core/FontEngineDefault/FontProvider.cpp
  96. 35 37
      Source/Core/FontEngineDefault/FontProvider.h
  97. 22 6
      Source/Core/FontEngineDefault/FontTypes.h
  98. 378 0
      Source/Core/FontEngineDefault/FreeTypeInterface.cpp
  99. 22 27
      Source/Core/FontEngineDefault/FreeTypeInterface.h
  100. 2 6
      Source/Core/FontEngineDefault/precompiled.h

+ 28 - 38
CMake/FileList.cmake

@@ -1,14 +1,6 @@
 # This file was auto-generated with gen_filelists.sh
 
 set(Core_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/BitmapFontDefinitions.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontFace.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontFaceHandle.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontFaceLayer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontProvider.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontFamily.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontParser.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/precompiled.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Clock.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ComputeProperty.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancerDefault.h
@@ -44,17 +36,6 @@ set(Core_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutlineInstancer.h
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadow.h
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadowInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontDatabaseDefault.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFace.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFamily.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceHandleDefault.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceLayer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontProvider.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FreeType/FontFace.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FreeType/FontFaceHandle.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FreeType/FontFamily.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FreeType/FontProvider.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FreeType/precompiled.h
     ${PROJECT_SOURCE_DIR}/Source/Core/IdNameMap.h
     ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.h
     ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBoxSpace.h
@@ -98,7 +79,6 @@ set(Core_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRow.h
     ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutTexture.h
     ${PROJECT_SOURCE_DIR}/Source/Core/TextureResource.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/UnicodeRange.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Utilities.h
     ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSlider.h
     ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSliderScroll.h
@@ -146,6 +126,7 @@ set(Core_PUB_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FileInterface.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FontEffect.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FontEffectInstancer.h
+    ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FontEngineInterface.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FontGlyph.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Geometry.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/GeometryUtilities.h
@@ -201,12 +182,6 @@ set(Core_PUB_HDR_FILES
 
 set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/BaseXMLParser.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontFace.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontFaceHandle.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontFaceLayer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontFamily.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontParser.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/BitmapFont/FontProvider.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Box.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Clock.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/ComputeProperty.cpp
@@ -254,24 +229,13 @@ set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/Factory.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FileInterface.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FileInterfaceDefault.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontDatabaseDefault.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffect.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectInstancer.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutline.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutlineInstancer.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadow.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadowInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFace.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceHandleDefault.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceLayer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFamily.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineInterface.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineInterfaceDefault.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontProvider.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FreeType/FontFace.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FreeType/FontFaceHandle.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FreeType/FontFamily.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FreeType/FontProvider.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Geometry.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/GeometryUtilities.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.cpp
@@ -335,7 +299,6 @@ set(Core_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/TransformPrimitive.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/TransformState.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/TypeConverter.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/UnicodeRange.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/URL.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Variant.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Vector3.cpp
@@ -441,6 +404,7 @@ set(Debugger_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementContextHook.h
     ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementInfo.h
     ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementLog.h
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/FontSource.h
     ${PROJECT_SOURCE_DIR}/Source/Debugger/Geometry.h
     ${PROJECT_SOURCE_DIR}/Source/Debugger/InfoSource.h
     ${PROJECT_SOURCE_DIR}/Source/Debugger/LogSource.h
@@ -468,6 +432,32 @@ set(Debugger_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Source/Debugger/SystemInterface.cpp
 )
 
+if(NOT NO_FONT_INTERFACE_DEFAULT)
+    set(Core_HDR_FILES
+        ${Core_HDR_FILES}
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.h
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFace.h
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFaceHandleDefault.h
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFaceLayer.h
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFamily.h
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontProvider.h
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontTypes.h
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FreeTypeInterface.h
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/precompiled.h
+    )
+
+    set(Core_SRC_FILES
+        ${Core_SRC_FILES}
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.cpp
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFace.cpp
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFaceHandleDefault.cpp
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFaceLayer.cpp
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFamily.cpp
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontProvider.cpp
+        ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FreeTypeInterface.cpp
+    )
+endif()
+
 set(LuaCore_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Core/Lua/Colourb.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Lua/Colourf.h

+ 4 - 0
CMake/SampleFileList.cmake

@@ -33,9 +33,13 @@ set(benchmark_SRC_FILES
 )
 
 set(bitmapfont_HDR_FILES
+    ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/FontEngineBitmap.h
+    ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/FontEngineInterfaceBitmap.h
 )
 
 set(bitmapfont_SRC_FILES
+    ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/FontEngineBitmap.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/FontEngineInterfaceBitmap.cpp
     ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/main.cpp
 )
 

+ 23 - 3
CMake/gen_filelists.sh

@@ -7,14 +7,17 @@ hdr='set(lib_HDR_FILES'
 masterpubhdr='set(MASTER_lib_PUB_HDR_FILES'
 pubhdr='set(lib_PUB_HDR_FILES'
 srcdir='${PROJECT_SOURCE_DIR}'
+fontdefaultbegin='if(NOT NO_FONT_INTERFACE_DEFAULT)'
+fontdefaultend='endif()'
 srcpath=Source
 hdrpath=Include/RmlUi
 luapath=Lua
+fontdefaultpath=FontEngineDefault
 
 printfiles() {
     # Print headers
     echo ${hdr/lib/$1} >>$file
-    find  $srcpath/$1 -maxdepth 3 -path */$luapath -prune -o \( -iname "*.h" -o -iname "*.hpp" \) -exec echo '    '$srcdir/{} \; 2>/dev/null | sort -f >>$file
+    find  $srcpath/$1 -maxdepth 3 -path */$luapath -prune -o -path */$fontdefaultpath -prune -o \( -iname "*.h" -o -iname "*.hpp" \) -exec echo '    '$srcdir/{} \; 2>/dev/null | sort -f >>$file
     echo -e ')\n' >>$file
     # Print master header for library
     echo ${masterpubhdr/lib/$1} >>$file
@@ -22,14 +25,29 @@ printfiles() {
     echo -e ')\n' >>$file
     # Print public headers sub directory
     echo ${pubhdr/lib/$1} >>$file
-    find  $hdrpath/$1 -maxdepth 3 -path */$luapath -prune -o \( -iname "*.h" -o -iname "*.inl" -o -iname "*.hpp" \) -exec echo '    '$srcdir/{} \; 2>/dev/null | sort -f >>$file
+    find  $hdrpath/$1 -maxdepth 3 -path */$luapath -prune -o -path */$fontdefaultpath -prune -o \( -iname "*.h" -o -iname "*.inl" -o -iname "*.hpp" \) -exec echo '    '$srcdir/{} \; 2>/dev/null | sort -f >>$file
     echo -e ')\n' >>$file
     # Print source files
     echo ${src/lib/$1} >>$file
-    find  $srcpath/$1 -maxdepth 3 -path */$luapath -prune -o -iname "*.cpp" -exec echo '    '$srcdir/{} \; 2>/dev/null | sort -f >>$file
+    find  $srcpath/$1 -maxdepth 3 -path */$luapath -prune -o -path */$fontdefaultpath -prune -o -iname "*.cpp" -exec echo '    '$srcdir/{} \; 2>/dev/null | sort -f >>$file
     echo -e ')\n' >>$file
 }
 
+printfontdefaultfiles() {
+    # Print headers
+	echo $fontdefaultbegin >>$file
+    echo '    '${hdr/lib/$1} >>$file
+    echo '        ${'$1'_HDR_FILES}' >>$file
+    find  $srcpath/$1/$fontdefaultpath -iname "*.h" -exec echo '        '$srcdir/{} \; 2>/dev/null | sort -f >>$file
+    echo -e '    )\n' >>$file
+    # Print source files
+    echo '    '${src/lib/$1} >>$file
+    echo '        ${'$1'_SRC_FILES}' >>$file
+    find  $srcpath/$1/$fontdefaultpath -iname "*.cpp" -exec echo '        '$srcdir/{} \; 2>/dev/null | sort -f >>$file
+    echo -e '    )' >>$file
+	echo -e $fontdefaultend'\n' >>$file
+}
+
 printluafiles() {
     # Print headers
     echo ${hdr/lib/Lua${1}} >>$file
@@ -51,6 +69,8 @@ for lib in "Core" "Controls" "Debugger"; do
     printfiles $lib
 done
 
+printfontdefaultfiles "Core"
+
 for lib in "Core" "Controls"; do
     printluafiles $lib
 done

+ 4 - 1
CMakeLists.txt

@@ -155,7 +155,7 @@ else(APPLE)
 	endif()
 endif(APPLE)
 
-option(NO_FONT_INTERFACE_DEFAULT "Do not build the font providers that come with the library" OFF)
+option(NO_FONT_INTERFACE_DEFAULT "Do not include the default font engine in the build. Allows building without the FreeType dependency, but a custom font engine must be created and set." OFF)
 if(NO_FONT_INTERFACE_DEFAULT)
 	add_definitions(-DRMLUI_NO_FONT_INTERFACE_DEFAULT)
 endif()
@@ -668,6 +668,9 @@ if(BUILD_SAMPLES)
 	install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/benchmark/data
 			DESTINATION ${SAMPLES_DIR}/basic/benchmark
 	)
+	install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/data
+			DESTINATION ${SAMPLES_DIR}/basic/bitmapfont
+	)
 	install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/demo/data
 			DESTINATION ${SAMPLES_DIR}/basic/demo
 	)

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

@@ -169,7 +169,6 @@ struct ComputedValues
 	float opacity = 1;
 
 	String font_family;
-	String font_charset; // empty is same as "U+0020-007E"
 	FontStyle font_style = FontStyle::Normal;
 	FontWeight font_weight = FontWeight::Normal;
 	float font_size = 12.f;

+ 6 - 4
Include/RmlUi/Core/Context.h

@@ -173,12 +173,14 @@ public:
 	/// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
 	bool ProcessKeyUp(Input::KeyIdentifier key_identifier, int key_modifier_state);
 
-	/// Sends a single character of text as text input into this context.
-	/// @param[in] character The UCS-2 character to send into this context.
+	/// Sends a single unicode character as text input into this context.
+	/// @param[in] character The unicode code point to send into this context.
 	/// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
-	bool ProcessTextInput(word character);
+	bool ProcessTextInput(Character character);
+	/// Sends a single ascii character as text input into this context.
+	bool ProcessTextInput(char character);
 	/// Sends a string of text as text input into this context.
-	/// @param[in] string The UCS-2 string to send into this context.
+	/// @param[in] string The UTF8 string to send into this context.
 	/// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
 	bool ProcessTextInput(const String& string);
 

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

@@ -123,9 +123,12 @@ RMLUICORE_API void SetFileInterface(FileInterface* file_interface);
 /// Returns RmlUi's file interface.
 RMLUICORE_API FileInterface* GetFileInterface();
 
-// Sets the interface through which all font requests are made.
-RMLUICORE_API void SetFontEngineInterface(FontEngineInterface* _font_interface);
-// Returns RmlUi's file interface.
+/// Sets the interface through which all font requests are made. This is not required to be called, but if it is
+/// it must be called before Initialise().
+/// @param[in] font_interface A non-owning pointer to the application-specified font engine interface.
+/// @lifetime The interface must be kept alive until after the call to Core::Shutdown.
+RMLUICORE_API void SetFontEngineInterface(FontEngineInterface* font_interface);
+/// Returns RmlUi's font interface.
 RMLUICORE_API FontEngineInterface* GetFontEngineInterface();
 	
 /// Creates a new element context.
@@ -151,6 +154,21 @@ RMLUICORE_API Context* GetContext(int index);
 /// @return The total number of active RmlUi contexts.
 RMLUICORE_API int GetNumContexts();
 
+/// Adds a new font face to the font engine. The face's family, style and weight will be determined from the face itself.
+/// @param[in] file_name The file to load the face from.
+/// @param[in] fallback_face True to use this font face for unknown characters in other font faces.
+/// @return True if the face was loaded successfully, false otherwise.
+RMLUICORE_API bool LoadFontFace(const String& file_name, bool fallback_face = false);
+/// Adds a new font face from memory to the font engine. The face's family, style and weight is given by the parameters.
+/// @param[in] data A pointer to the data.
+/// @param[in] data_size Size of the data in bytes.
+/// @param[in] family The family to register the font as.
+/// @param[in] style The style to register the font as.
+/// @param[in] weight The weight to register the font as.
+/// @param[in] fallback_face True to use this font face for unknown characters in other font faces.
+/// @return True if the face was loaded successfully, false otherwise.
+RMLUICORE_API bool LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face = false);
+
 /// Registers a generic RmlUi plugin.
 RMLUICORE_API void RegisterPlugin(Plugin* plugin);
 

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

@@ -51,10 +51,10 @@ public:
 	/// Sets the raw string this text element contains. The actual rendered text may be different due to whitespace
 	/// formatting.
 	/// @param[in] text The new string to set on this element.
-	virtual void SetText(const WString& text) = 0;
+	virtual void SetText(const String& text) = 0;
 	/// Returns the raw string this text element contains.
 	/// @return This element's raw text.
-	virtual const WString& GetText() const = 0;
+	virtual const String& GetText() const = 0;
 
 	/// Generates a token of text from this element, returning only the width.
 	/// @param[out] token_width The window (in pixels) of the token.
@@ -70,14 +70,14 @@ public:
 	/// @param[in] right_spacing_width The width (in pixels) of the spacing (consisting of margins, padding, etc) that must be remaining on the right of the line if the last of the text is rendered onto this line.
 	/// @param[in] trim_whitespace_prefix If we're collapsing whitespace, whether or not to remove all prefixing whitespace or collapse it down to a single space.
 	/// @return True if the line reached the end of the element's text, false if not.
-	virtual bool GenerateLine(WString& line, int& line_length, float& line_width, int line_begin, float maximum_line_width, float right_spacing_width, bool trim_whitespace_prefix) = 0;
+	virtual bool GenerateLine(String& line, int& line_length, float& line_width, int line_begin, float maximum_line_width, float right_spacing_width, bool trim_whitespace_prefix) = 0;
 
 	/// Clears all lines of generated text and prepares the element for generating new lines.
 	virtual void ClearLines() = 0;
 	/// Adds a new line into the text element.
 	/// @param[in] line_position The position of this line, as an offset from the first line.
 	/// @param[in] line The contents of the line.
-	virtual void AddLine(const Vector2f& line_position, const WString& line) = 0;
+	virtual void AddLine(const Vector2f& line_position, const String& line) = 0;
 
 	/// Prevents the element from dirtying its document's layout when its text is changed.
 	virtual void SuppressAutoLayout() = 0;

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

@@ -77,10 +77,6 @@ public:
 	/// @param[in] tag Class name to search for.
 	static void GetElementsByClassName(ElementList& elements, Element* root_element, const String& class_name);
 
-	/// Returns an element's font face.
-	/// @param[in] element The element to determine the font face for.
-	/// @return The element's font face. This will be nullptr if no valid RCSS font styles have been set up for this element.
-	static FontFaceHandle GetFontFaceHandle(const Style::ComputedValues& computed_values);
 	/// Returns an element's density-independent pixel ratio, defined by it's context
 	/// @param[in] element The element to determine the density-independent pixel ratio for.
 	/// @return The density-independent pixel ratio of the context, or 1.0 if no context assigned.
@@ -89,7 +85,7 @@ public:
 	/// @param[in] element The element to measure the string from.
 	/// @param[in] string The string to measure.
 	/// @return The string width, in pixels.
-	static int GetStringWidth(Element* element, const WString& string);
+	static int GetStringWidth(Element* element, const String& string);
 
 	/// Bind and instance all event attributes on the given element onto the element
 	/// @param element Element to bind events on

+ 52 - 40
Include/RmlUi/Core/FontEngineInterface.h

@@ -28,7 +28,6 @@
 #ifndef RMLUICOREFONTENGINEINTERFACE_H
 #define RMLUICOREFONTENGINEINTERFACE_H
 
-#include "Traits.h"
 #include "Header.h"
 #include "Types.h"
 #include "Geometry.h"
@@ -42,71 +41,84 @@ public:
 	FontEngineInterface();
 	virtual ~FontEngineInterface();
 
-	/// Adds a new font face to the database. The face's family, style and weight will be determined from the face itself.
+	/// Called by RmlUi when it wants to load a font face from file.
 	/// @param[in] file_name The file to load the face from.
+	/// @param[in] fallback_face True to use this font face for unknown characters in other font faces.
 	/// @return True if the face was loaded successfully, false otherwise.
-	virtual bool LoadFontFace(const String& file_name);
+	virtual bool LoadFontFace(const String& file_name, bool fallback_face);
 
-	/// Returns a handle to a font face that can be used to position and render text. This will return the closest match
-	/// it can find, but in the event a font family is requested that does not exist, NULL will be returned instead of a
-	/// valid handle.
+	/// Called by RmlUi when it wants to load a font face from memory, registered using the provided family, style, and weight.
+	/// @param[in] data A pointer to the data.
+	/// @param[in] data_size Size of the data in bytes.
+	/// @param[in] family The family to register the font as.
+	/// @param[in] style The style to register the font as.
+	/// @param[in] weight The weight to register the font as.
+	/// @param[in] fallback_face True to use this font face for unknown characters in other font faces.
+	/// @return True if the face was loaded successfully, false otherwise.
+	/// Note: The debugger plugin will load its embedded font faces through this method using the family name 'rmlui-debugger-font'.
+	virtual bool LoadFontFace(const byte* data, int data_size, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face);
+
+	/// Called by RmlUi when a font configuration is resolved for an element. Should return a handle that 
+	/// can later be used to resolve properties of the face, and generate string geometry to be rendered.
 	/// @param[in] family The family of the desired font handle.
-	/// @param[in] charset The set of characters required in the font face, as a comma-separated list of unicode ranges.
 	/// @param[in] style The style of the desired font handle.
 	/// @param[in] weight The weight of the desired font handle.
 	/// @param[in] size The size of desired handle, in points.
 	/// @return A valid handle if a matching (or closely matching) font face was found, NULL otherwise.
-	virtual FontFaceHandle GetFontFaceHandle(const String& family, const String& charset, Style::FontStyle style, Style::FontWeight weight, int size);
+	virtual FontFaceHandle GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size);
 
-	/// Generates, if required, the layer configuration for a given array of font effects.
-	/// @param[in] FontHandle
+	/// Called by RmlUi when a list of font effects is resolved for an element with a given font face.
+	/// @param[in] handle The font handle.
 	/// @param[in] font_effects The list of font effects to generate the configuration for.
-	/// @return The index to use when generating geometry using this configuration.
-	virtual int GenerateLayerConfiguration(FontFaceHandle, const FontEffectList &font_effects) const;
-
-	/// Returns the average advance of all glyphs in this font face.
-	/// @param[in] FontHandle
-	/// @return An approximate width of the characters in this font face.
-	virtual int GetCharacterWidth(FontFaceHandle) const;
+	/// @return A handle to the prepared font effects which will be used when generating geometry for a string.
+	virtual FontEffectsHandle PrepareFontEffects(FontFaceHandle handle, const FontEffectList &font_effects);
 
-	/// Returns the point size of this font face.
-	/// @param[in] FontHandle
+	/// Should return the point size of this font face.
+	/// @param[in] handle The font handle.
 	/// @return The face's point size.
-	virtual int GetSize(FontFaceHandle) const;
-	/// Returns the pixel height of a lower-case x in this font face.
-	/// @param[in] FontHandle
+	virtual int GetSize(FontFaceHandle handle);
+	/// Should return the pixel height of a lower-case x in this font face.
+	/// @param[in] handle The font handle.
 	/// @return The height of a lower-case x.
-	virtual int GetXHeight(FontFaceHandle) const;
-	/// Returns the default height between this font face's baselines.
-	/// @param[in] FontHandle
+	virtual int GetXHeight(FontFaceHandle handle);
+	/// Should return the default height between this font face's baselines.
+	/// @param[in] handle The font handle.
 	/// @return The default line height.
-	virtual int GetLineHeight(FontFaceHandle) const;
+	virtual int GetLineHeight(FontFaceHandle handle);
 
-	/// Returns the font's baseline, as a pixel offset from the bottom of the font.
-	/// @param[in] FontHandle
+	/// Should return the font's baseline, as a pixel offset from the bottom of the font.
+	/// @param[in] handle The font handle.
 	/// @return The font's baseline.
-	virtual int GetBaseline(FontFaceHandle) const;
+	virtual int GetBaseline(FontFaceHandle handle);
 
-	/// Returns the font's underline, as a pixel offset from the bottom of the font.
-	/// @param[in] FontHandle
-	/// @return The font's underline thickness.
-	virtual float GetUnderline(FontFaceHandle, float *thickness) const;
+	/// Should return the font's underline, as a pixel offset from the bottom of the font.
+	/// @param[in] handle The font handle.
+	/// @param[out] thickness The font's underline thickness in pixels.
+	/// @return The underline pixel offset.
+	virtual float GetUnderline(FontFaceHandle handle, float &thickness);
 
-	/// Returns the width a string will take up if rendered with this handle.
-	/// @param[in] FontHandle
+	/// Called by RmlUi when it wants to retrieve the width of a string when rendered with this handle.
+	/// @param[in] handle The font handle.
 	/// @param[in] string The string to measure.
 	/// @param[in] prior_character The optionally-specified character that immediately precedes the string. This may have an impact on the string width due to kerning.
 	/// @return The width, in pixels, this string will occupy if rendered with this handle.
-	virtual int GetStringWidth(FontFaceHandle, const WString& string, word prior_character = 0);
+	virtual int GetStringWidth(FontFaceHandle handle, const String& string, Character prior_character = Character::Null);
 
-	/// Generates the geometry required to render a single line of text.
-	/// @param[out] geometry An array of geometries to generate the geometry into.
-	/// @param[in] FontHandle
+	/// Called by RmlUi when it wants to retrieve the geometry required to render a single line of text.
+	/// @param[in] face_handle The font handle.
+	/// @param[in] font_effects_handle The handle to the prepared font effects for which the geometry should be generated.
 	/// @param[in] string The string to render.
 	/// @param[in] position The position of the baseline of the first character to render.
 	/// @param[in] colour The colour to render the text.
+	/// @param[out] geometry An array of geometries to generate the geometry into.
 	/// @return The width, in pixels, of the string geometry.
-	virtual int GenerateString(FontFaceHandle, GeometryList& geometry, const WString& string, const Vector2f& position, const Colourb& colour, int layer_configuration) const;
+	virtual int GenerateString(FontFaceHandle face_handle, FontEffectsHandle font_effects_handle, const String& string, const Vector2f& position, const Colourb& colour, GeometryList& geometry);
+
+	/// Called by RmlUi to determine if the text geometry is required to be re-generated. Whenever the returned version
+	/// is changed, all geometry belonging to the given face handle will be re-generated.
+	/// @param[in] face_handle The font handle.
+	/// @return The version required for using the geometry.
+	virtual int GetVersion(FontFaceHandle handle);
 };
 
 }

+ 20 - 10
Include/RmlUi/Core/FontGlyph.h

@@ -29,7 +29,7 @@
 #ifndef RMLUICOREFONTGLYPH_H
 #define RMLUICOREFONTGLYPH_H
 
-#include <vector>
+#include "Types.h"
 
 namespace Rml {
 namespace Core {
@@ -43,13 +43,8 @@ namespace Core {
 class FontGlyph
 {
 public:
-	FontGlyph() : character(0), dimensions(0,0), bearing(0,0), advance(0), bitmap_data(nullptr),
-		bitmap_dimensions(0,0)
-	{
-	}
-
-	/// The unicode code point for this glyph.
-	word character;
+	FontGlyph() : dimensions(0,0), bearing(0,0), advance(0), bitmap_data(nullptr), bitmap_dimensions(0,0)
+	{}
 
 	/// The glyph's bounding box. Not to be confused with the dimensions of the glyph's bitmap!
 	Vector2i dimensions;
@@ -62,12 +57,27 @@ public:
 
 	/// 8-bit opacity information for the glyph's bitmap. The size of the data is given by the
 	/// dimensions, below. This will be nullptr if the glyph has no bitmap data.
-	byte* bitmap_data;
+	const byte* bitmap_data;
 	/// The dimensions of the glyph's bitmap.
 	Vector2i bitmap_dimensions;
+
+	// Bitmap_data may point to this member or another font glyph data.
+	UniquePtr<byte[]> bitmap_owned_data;
+
+	// Create a copy with its bitmap data owned by another glyph.
+	FontGlyph WeakCopy() const 
+	{
+		FontGlyph glyph;
+		glyph.dimensions = dimensions;
+		glyph.bearing = bearing;
+		glyph.advance = advance;
+		glyph.bitmap_data = bitmap_data;
+		glyph.bitmap_dimensions = bitmap_dimensions;
+		return glyph;
+	}
 };
 
-typedef std::vector< FontGlyph > FontGlyphList;
+using FontGlyphMap = UnorderedMap<Character, FontGlyph>;
 
 }
 }

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

@@ -113,7 +113,6 @@ enum class PropertyId : uint16_t
 	Color,
 	ImageColor,
 	FontFamily,
-	FontCharset,
 	FontStyle,
 	FontWeight,
 	FontSize,

+ 115 - 14
Include/RmlUi/Core/StringUtilities.h

@@ -29,6 +29,8 @@
 #ifndef RMLUICORESTRINGUTILITIES_H
 #define RMLUICORESTRINGUTILITIES_H
 
+#include <algorithm>
+#include <stddef.h>
 #include "Header.h"
 #include "Types.h"
 
@@ -46,6 +48,7 @@ namespace Core {
 	#define strncasecmp strnicmp
 #endif
 
+class StringView;
 
 /// Construct a string using sprintf-style syntax.
 RMLUICORE_API String CreateString(size_t max_size, const char* format, ...);
@@ -76,16 +79,6 @@ namespace StringUtilities
 	/// @param[in] delimiter Delimiter to insert between the individual values.
 	RMLUICORE_API void JoinString(String& string, const StringList& string_list, const char delimiter = ',');
 
-	/// Converts a string in UTF-8 encoding to a wide string in UCS-2 encoding. The UCS-2 words will
-	/// be encoded as either big- or little-endian, depending on the host processor.
-	/// Reports a warning if the conversion fails.
-	RMLUICORE_API WString ToUCS2(const String& str);
-
-	/// Converts a wide string in UCS-2 encoding into a string in UTF-8 encoding. This
-	/// function assumes the endianness of the input words to be the same as the host processor.
-	/// Reports a warning if the conversion fails.
-	RMLUICORE_API String ToUTF8(const WString& wstr);
-
 	/// Converts upper-case characters in string to lower-case.
 	RMLUICORE_API String ToLower(const String& string);
 
@@ -95,8 +88,6 @@ namespace StringUtilities
 	RMLUICORE_API String Replace(String subject, char search, char replace);
 
 	/// Checks if a given value is a whitespace character.
-	/// @param[in] x The character to evaluate.
-	/// @return True if the character is whitespace, false otherwise.
 	template < typename CharacterType >
 	inline bool IsWhitespace(CharacterType x)
 	{
@@ -104,8 +95,6 @@ namespace StringUtilities
 	}
 
 	/// Strip whitespace characters from the beginning and end of a string.
-	/// @param[in] string The string to trim.
-	/// @return The stripped string.
 	RMLUICORE_API String StripWhitespace(const String& string);
 
 	/// Operator for STL containers using strings.
@@ -113,8 +102,120 @@ namespace StringUtilities
 	{
 		bool operator()(const String& lhs, const String& rhs) const;
 	};
+
+	// Decode the first code point in a zero-terminated UTF-8 string.
+	RMLUICORE_API Character ToCharacter(const char* p);
+
+	// Encode a single code point as a UTF-8 string.
+	RMLUICORE_API String ToUTF8(Character character);
+
+	// Encode an array of code points as a UTF-8 string.
+	RMLUICORE_API String ToUTF8(const Character* characters, int num_characters);
+
+	/// Returns number of characters in a UTF-8 string.
+	RMLUICORE_API size_t LengthUTF8(StringView string_view);
+
+	// Seek forward in a UTF-8 string, skipping continuation bytes.
+	inline const char* SeekForwardUTF8(const char* p, const char* p_end)
+	{
+		while (p != p_end && (*p & 0b1100'0000) == 0b1000'0000)
+			++p;
+		return p;
+	}
+	// Seek backward in a UTF-8 string, skipping continuation bytes.
+	inline const char* SeekBackwardUTF8(const char* p, const char* p_begin)
+	{
+		while ((p + 1) != p_begin && (*p & 0b1100'0000) == 0b1000'0000)
+			--p;
+		return p;
+	}
+
+
+	/// Converts a string in UTF-8 encoding to a u16string in UTF-16 encoding.
+	/// Reports a warning if some or all characters could not be converted.
+	RMLUICORE_API U16String ToUTF16(const String& str);
+
+	/// Converts a u16string in UTF-16 encoding into a string in UTF-8 encoding.
+	/// Reports a warning if some or all characters could not be converted.
+	RMLUICORE_API String ToUTF8(const U16String& u16str);
 }
 
+
+/*
+	A poor man's string view. 
+	
+	The string view is agnostic to the underlying encoding, any operation will strictly operate on bytes.
+*/
+
+class RMLUICORE_API StringView {
+public:
+	StringView(const char* p_begin, const char* p_end);
+	StringView(const String& string);
+	StringView(const String& string, size_t offset);
+	StringView(const String& string, size_t offset, size_t count);
+
+	// String comparison to another view
+	bool operator==(const StringView& other) const;
+	inline bool operator!=(const StringView& other) const { return !(*this == other); }
+
+	inline const char* begin() const { return p_begin; }
+	inline const char* end() const { return p_end; }
+
+	inline size_t size() const { return p_end - p_begin; }
+
+private:
+	const char* p_begin;
+	const char* p_end;
+};
+
+
+/*
+	An iterator for UTF-8 strings. 
+
+	The increment and decrement operations will move to the beginning of the next or the previous
+	UTF-8 character, respectively. The dereference operator will resolve the current code point.
+
+*/
+
+class RMLUICORE_API StringIteratorU8 {
+public:
+	StringIteratorU8(const char* p_begin, const char* p, const char* p_end);
+	StringIteratorU8(const String& string);
+	StringIteratorU8(const String& string, size_t offset);
+	StringIteratorU8(const String& string, size_t offset, size_t count);
+
+	// Seeks forward to the next UTF-8 character. Iterator must be valid.
+	StringIteratorU8& operator++();
+	// Seeks back to the previous UTF-8 character. Iterator must be valid.
+	StringIteratorU8& operator--();
+
+	// Returns the codepoint at the current position. The iterator must be dereferencable.
+	inline Character operator*() const { return StringUtilities::ToCharacter(p); }
+
+	// Returns false when the iterator is located just outside the valid part of the string.
+	inline operator bool() const { return (p != view.begin() - 1) && (p != view.end()); }
+
+	bool operator==(const StringIteratorU8& other) const { return p == other.p; }
+	bool operator!=(const StringIteratorU8& other) const { return !(*this == other); }
+
+	// Return a pointer to the current position.
+	inline const char* Get() const { return p; }
+
+	// Return offset from the beginning of string. Note: Can return negative if decremented.
+	std::ptrdiff_t Offset() const { return p - view.begin(); }
+
+private:
+	StringView view;
+	// 'p' can be dereferenced if and only if inside [view.begin, view.end)
+	const char* p;
+
+	inline void SeekForward();
+	inline void SeekBack();
+};
+
+
+
+
 }
 }
 

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

@@ -86,11 +86,11 @@ public:
 
 	/// Set clipboard text.
 	/// @param[in] text Text to apply to clipboard.
-	virtual void SetClipboardText(const WString& text);
+	virtual void SetClipboardText(const String& text);
 
 	/// Get clipboard text.
 	/// @param[out] text Retrieved text from clipboard.
-	virtual void GetClipboardText(WString& text);
+	virtual void GetClipboardText(String& text);
 
 	/// Activate keyboard (for touchscreen devices)
 	virtual void ActivateKeyboard();

+ 22 - 4
Include/RmlUi/Core/Texture.h

@@ -31,6 +31,7 @@
 
 #include "Header.h"
 #include "Types.h"
+#include <functional>
 
 namespace Rml {
 namespace Core {
@@ -38,6 +39,16 @@ namespace Core {
 class TextureResource;
 class RenderInterface;
 
+/*
+	Callback function for generating textures.
+	/// @param[in] name The name used to set the texture.
+	/// @param[out] data The raw data of the texture, each pixel has four 8-bit channels: red-green-blue-alpha.
+	/// @param[out] dimensions The width and height of the generated texture.
+	/// @return True on success.
+*/
+using TextureCallback = std::function<bool(const String& name, UniquePtr<const byte[]>& data, Vector2i& dimensions)>;
+
+
 /**
 	Abstraction of a two-dimensional texture image, with an application-specific texture handle.
 
@@ -47,11 +58,15 @@ class RenderInterface;
 struct RMLUICORE_API Texture
 {
 public:
-	/// Attempts to load a texture.
-	/// @param[in] source The name of the texture.
+	/// Set the texture source and path. The texture is added to the global cache and only loaded on first use.
+	/// @param[in] source The source of the texture.
 	/// @param[in] source_path The path of the resource that is requesting the texture (ie, the RCSS file in which it was specified, etc).
-	/// @return True if the texture loaded successfully, false if not.
-	bool Load(const String& source, const String& source_path = "");
+	void Set(const String& source, const String& source_path = "");
+
+	/// Set a callback function for generating the texture on first use. The texture is never added to the global cache.
+	/// @param[in] name The name of the texture.
+	/// @param[in] callback The callback function which generates the data of the texture, see TextureCallback.
+	void Set(const String& name, const TextureCallback& callback);
 
 	/// Returns the texture's source name. This is usually the name of the file the texture was loaded from.
 	/// @return The name of the this texture's source. This will be the empty string if this texture is not loaded.
@@ -65,6 +80,9 @@ public:
 	/// @return The texture's dimensions. This will be (0, 0) if the texture isn't loaded.
 	Vector2i GetDimensions(RenderInterface* render_interface) const;
 
+	/// Removes the underlying texture resource from the texture database, thereby releasing the texture once all references to it are removed.
+	void RemoveDatabaseCache() const;
+
 	/// Returns true if the texture points to the same underlying resource.
 	bool operator==(const Texture&) const;
 

+ 2 - 2
Include/RmlUi/Core/TypeConverter.inl

@@ -105,7 +105,7 @@ PASS_THROUGH(unsigned int);
 PASS_THROUGH(float);
 PASS_THROUGH(bool);
 PASS_THROUGH(char);
-PASS_THROUGH(word);
+PASS_THROUGH(Character);
 PASS_THROUGH(Vector2i);
 PASS_THROUGH(Vector2f);
 PASS_THROUGH(Vector3i);
@@ -148,7 +148,7 @@ BASIC_CONVERTER_BOOL(float, bool);
 BASIC_CONVERTER(float, int);
 BASIC_CONVERTER(float, unsigned int);
 
-BASIC_CONVERTER(char, word);
+BASIC_CONVERTER(char, Character);
 
 /////////////////////////////////////////////////
 // From string converters

+ 8 - 11
Include/RmlUi/Core/Types.h

@@ -57,20 +57,16 @@ namespace Rml {
 namespace Core {
 
 // Commonly used basic types
-typedef unsigned char byte;
-typedef wchar_t word;
-typedef double Time;
-typedef void* ScriptObject;
+using byte = unsigned char;
+using Time = double;
+using ScriptObject = void*;
+
+// Unicode code point
+enum class Character : char32_t { Null, Replacement = 0xfffd };
 
 }
 }
 
-#ifdef RMLUI_PLATFORM_WIN32
-typedef unsigned __int64 uint64_t;
-#else
-#include <inttypes.h>
-#endif
-
 #include "Colour.h"
 #include "Vector2.h"
 #include "Vector3.h"
@@ -119,11 +115,12 @@ using TextureHandle = uintptr_t;
 using CompiledGeometryHandle = uintptr_t;
 using DecoratorDataHandle = uintptr_t;
 using FontFaceHandle = uintptr_t;
+using FontEffectsHandle = uintptr_t;
 
 // Strings
 using String = std::string;
-using WString = std::wstring;
 using StringList = std::vector< String >;
+using U16String = std::u16string;
 
 // Smart pointer types
 template<typename T>

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

@@ -125,7 +125,7 @@ private:
 	void Set(const char value);
 	void Set(const float value);
 	void Set(const int value);
-	void Set(const word value);
+	void Set(const Character value);
 	void Set(const char* value);
 	void Set(void* value);
 	void Set(const Vector2f& value);

+ 1 - 1
Include/RmlUi/Core/Variant.inl

@@ -75,7 +75,7 @@ bool Variant::GetInto(T& value) const
 		break;
 
 	case WORD:
-		return TypeConverter< word, T >::Convert(*(word*)data, value);
+		return TypeConverter< Character, T >::Convert(*(Character*)data, value);
 		break;
 
 	case VECTOR2:

+ 0 - 270
Samples/assets/Arial.fnt

@@ -1,270 +0,0 @@
-<?xml version="1.0"?>
-<font>
-  <info face="Arial" size="26" bold="0" italic="0" src="Arial_0.tga"/>
-  <common lineHeight="26" base="26" scaleW="1024" scaleH="1024" />
-  <chars count="191">
-    <char id="32" x="170" y="40" width="1" height="1" xoffset="0" yoffset="21" xadvance="6" />
-    <char id="33" x="643" y="19" width="2" height="17" xoffset="3" yoffset="4" xadvance="8" />
-    <char id="34" x="63" y="41" width="6" height="6" xoffset="1" yoffset="4" xadvance="8" />
-    <char id="35" x="84" y="23" width="13" height="17" xoffset="0" yoffset="4" xadvance="13" />
-    <char id="36" x="511" y="0" width="11" height="20" xoffset="1" yoffset="3" xadvance="13" />
-    <char id="37" x="724" y="0" width="18" height="17" xoffset="1" yoffset="4" xadvance="20" />
-    <char id="38" x="56" y="23" width="13" height="17" xoffset="1" yoffset="4" xadvance="15" />
-    <char id="39" x="77" y="41" width="2" height="6" xoffset="1" yoffset="4" xadvance="4" />
-    <char id="40" x="91" y="0" width="5" height="22" xoffset="1" yoffset="4" xadvance="8" />
-    <char id="41" x="97" y="0" width="5" height="22" xoffset="2" yoffset="4" xadvance="8" />
-    <char id="42" x="54" y="41" width="8" height="7" xoffset="1" yoffset="4" xadvance="9" />
-    <char id="43" x="916" y="18" width="12" height="12" xoffset="1" yoffset="7" xadvance="13" />
-    <char id="44" x="80" y="41" width="2" height="5" xoffset="2" yoffset="19" xadvance="6" />
-    <char id="45" x="149" y="40" width="7" height="2" xoffset="0" yoffset="14" xadvance="8" />
-    <char id="46" x="167" y="40" width="2" height="2" xoffset="2" yoffset="19" xadvance="6" />
-    <char id="47" x="604" y="19" width="7" height="17" xoffset="0" yoffset="4" xadvance="6" />
-    <char id="48" x="273" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="49" x="620" y="19" width="6" height="17" xoffset="3" yoffset="4" xadvance="13" />
-    <char id="50" x="285" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="51" x="345" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="52" x="441" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="53" x="453" y="21" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="54" x="189" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="55" x="261" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="56" x="201" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="57" x="213" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="58" x="913" y="18" width="2" height="13" xoffset="2" yoffset="8" xadvance="6" />
-    <char id="59" x="717" y="18" width="2" height="16" xoffset="2" yoffset="8" xadvance="6" />
-    <char id="60" x="941" y="18" width="10" height="11" xoffset="1" yoffset="7" xadvance="13" />
-    <char id="61" x="32" y="41" width="10" height="7" xoffset="1" yoffset="9" xadvance="13" />
-    <char id="62" x="952" y="18" width="10" height="11" xoffset="1" yoffset="7" xadvance="13" />
-    <char id="63" x="225" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="64" x="0" y="0" width="21" height="22" xoffset="1" yoffset="4" xadvance="23" />
-    <char id="65" x="816" y="0" width="17" height="17" xoffset="-1" yoffset="4" xadvance="15" />
-    <char id="66" x="124" y="22" width="12" height="17" xoffset="2" yoffset="4" xadvance="15" />
-    <char id="67" x="919" y="0" width="15" height="17" xoffset="1" yoffset="4" xadvance="17" />
-    <char id="68" x="951" y="0" width="14" height="17" xoffset="2" yoffset="4" xadvance="17" />
-    <char id="69" x="163" y="22" width="12" height="17" xoffset="2" yoffset="4" xadvance="15" />
-    <char id="70" x="237" y="22" width="11" height="17" xoffset="2" yoffset="4" xadvance="14" />
-    <char id="71" x="869" y="0" width="16" height="17" xoffset="1" yoffset="4" xadvance="18" />
-    <char id="72" x="42" y="23" width="13" height="17" xoffset="2" yoffset="4" xadvance="17" />
-    <char id="73" x="640" y="19" width="2" height="17" xoffset="2" yoffset="4" xadvance="6" />
-    <char id="74" x="576" y="19" width="9" height="17" xoffset="1" yoffset="4" xadvance="12" />
-    <char id="75" x="996" y="0" width="14" height="17" xoffset="2" yoffset="4" xadvance="15" />
-    <char id="76" x="543" y="19" width="10" height="17" xoffset="2" yoffset="4" xadvance="13" />
-    <char id="77" x="935" y="0" width="15" height="17" xoffset="2" yoffset="4" xadvance="19" />
-    <char id="78" x="70" y="23" width="13" height="17" xoffset="2" yoffset="4" xadvance="17" />
-    <char id="79" x="852" y="0" width="16" height="17" xoffset="1" yoffset="4" xadvance="18" />
-    <char id="80" x="98" y="23" width="12" height="17" xoffset="2" yoffset="4" xadvance="15" />
-    <char id="81" x="560" y="0" width="16" height="18" xoffset="1" yoffset="4" xadvance="18" />
-    <char id="82" x="981" y="0" width="14" height="17" xoffset="2" yoffset="4" xadvance="17" />
-    <char id="83" x="28" y="23" width="13" height="17" xoffset="1" yoffset="4" xadvance="15" />
-    <char id="84" x="1011" y="0" width="12" height="17" xoffset="1" yoffset="4" xadvance="14" />
-    <char id="85" x="14" y="23" width="13" height="17" xoffset="2" yoffset="4" xadvance="17" />
-    <char id="86" x="798" y="0" width="17" height="17" xoffset="-1" yoffset="4" xadvance="15" />
-    <char id="87" x="657" y="0" width="23" height="17" xoffset="0" yoffset="4" xadvance="23" />
-    <char id="88" x="903" y="0" width="15" height="17" xoffset="0" yoffset="4" xadvance="15" />
-    <char id="89" x="966" y="0" width="14" height="17" xoffset="0" yoffset="4" xadvance="14" />
-    <char id="90" x="0" y="23" width="13" height="17" xoffset="0" yoffset="4" xadvance="14" />
-    <char id="91" x="108" y="0" width="4" height="22" xoffset="1" yoffset="4" xadvance="6" />
-    <char id="92" x="612" y="19" width="7" height="17" xoffset="0" yoffset="4" xadvance="6" />
-    <char id="93" x="103" y="0" width="4" height="22" xoffset="1" yoffset="4" xadvance="6" />
-    <char id="94" x="983" y="18" width="10" height="9" xoffset="1" yoffset="4" xadvance="12" />
-    <char id="95" x="111" y="41" width="14" height="2" xoffset="-1" yoffset="24" xadvance="13" />
-    <char id="96" x="106" y="41" width="4" height="3" xoffset="1" yoffset="4" xadvance="8" />
-    <char id="97" x="814" y="18" width="11" height="13" xoffset="1" yoffset="8" xadvance="13" />
-    <char id="98" x="477" y="21" width="10" height="17" xoffset="1" yoffset="4" xadvance="12" />
-    <char id="99" x="850" y="18" width="10" height="13" xoffset="1" yoffset="8" xadvance="12" />
-    <char id="100" x="565" y="19" width="10" height="17" xoffset="1" yoffset="4" xadvance="12" />
-    <char id="101" x="826" y="18" width="11" height="13" xoffset="1" yoffset="8" xadvance="13" />
-    <char id="102" x="595" y="19" width="8" height="17" xoffset="0" yoffset="4" xadvance="7" />
-    <char id="103" x="614" y="0" width="10" height="18" xoffset="1" yoffset="8" xadvance="12" />
-    <char id="104" x="554" y="19" width="10" height="17" xoffset="1" yoffset="4" xadvance="12" />
-    <char id="105" x="637" y="19" width="2" height="17" xoffset="1" yoffset="4" xadvance="5" />
-    <char id="106" x="85" y="0" width="5" height="22" xoffset="-2" yoffset="4" xadvance="4" />
-    <char id="107" x="249" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="11" />
-    <char id="108" x="646" y="19" width="2" height="17" xoffset="1" yoffset="4" xadvance="4" />
-    <char id="109" x="771" y="18" width="16" height="13" xoffset="1" yoffset="8" xadvance="18" />
-    <char id="110" x="894" y="18" width="10" height="13" xoffset="1" yoffset="8" xadvance="12" />
-    <char id="111" x="802" y="18" width="11" height="13" xoffset="1" yoffset="8" xadvance="13" />
-    <char id="112" x="636" y="0" width="10" height="18" xoffset="1" yoffset="8" xadvance="12" />
-    <char id="113" x="591" y="0" width="11" height="18" xoffset="0" yoffset="8" xadvance="12" />
-    <char id="114" x="905" y="18" width="7" height="13" xoffset="1" yoffset="8" xadvance="8" />
-    <char id="115" x="883" y="18" width="10" height="13" xoffset="1" yoffset="8" xadvance="12" />
-    <char id="116" x="647" y="0" width="6" height="18" xoffset="0" yoffset="3" xadvance="6" />
-    <char id="117" x="861" y="18" width="10" height="13" xoffset="1" yoffset="8" xadvance="12" />
-    <char id="118" x="788" y="18" width="13" height="13" xoffset="-1" yoffset="8" xadvance="11" />
-    <char id="119" x="753" y="18" width="17" height="13" xoffset="-1" yoffset="8" xadvance="15" />
-    <char id="120" x="838" y="18" width="11" height="13" xoffset="0" yoffset="8" xadvance="11" />
-    <char id="121" x="577" y="0" width="13" height="18" xoffset="-1" yoffset="8" xadvance="11" />
-    <char id="122" x="872" y="18" width="10" height="13" xoffset="0" yoffset="8" xadvance="11" />
-    <char id="123" x="71" y="0" width="6" height="22" xoffset="1" yoffset="4" xadvance="8" />
-    <char id="124" x="113" y="0" width="2" height="22" xoffset="2" yoffset="4" xadvance="6" />
-    <char id="125" x="78" y="0" width="6" height="22" xoffset="1" yoffset="4" xadvance="8" />
-    <char id="126" x="83" y="41" width="11" height="4" xoffset="1" yoffset="11" xadvance="13" />
-    <char id="160" x="172" y="40" width="1" height="1" xoffset="0" yoffset="21" xadvance="6" />
-    <char id="161" x="654" y="0" width="2" height="18" xoffset="3" yoffset="8" xadvance="8" />
-    <char id="162" x="60" y="0" width="10" height="22" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="163" x="111" y="23" width="12" height="17" xoffset="0" yoffset="4" xadvance="13" />
-    <char id="164" x="929" y="18" width="11" height="11" xoffset="1" yoffset="7" xadvance="13" />
-    <char id="165" x="176" y="22" width="12" height="17" xoffset="0" yoffset="4" xadvance="13" />
-    <char id="166" x="116" y="0" width="2" height="22" xoffset="2" yoffset="4" xadvance="6" />
-    <char id="167" x="48" y="0" width="11" height="22" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="168" x="157" y="40" width="6" height="2" xoffset="1" yoffset="4" xadvance="8" />
-    <char id="169" x="762" y="0" width="17" height="17" xoffset="0" yoffset="4" xadvance="17" />
-    <char id="170" x="8" y="41" width="7" height="8" xoffset="1" yoffset="4" xadvance="9" />
-    <char id="171" x="973" y="18" width="9" height="10" xoffset="1" yoffset="10" xadvance="13" />
-    <char id="172" x="43" y="41" width="10" height="7" xoffset="1" yoffset="9" xadvance="13" />
-    <char id="173" x="141" y="40" width="7" height="2" xoffset="0" yoffset="14" xadvance="8" />
-    <char id="174" x="834" y="0" width="17" height="17" xoffset="0" yoffset="4" xadvance="17" />
-    <char id="175" x="126" y="40" width="14" height="2" xoffset="-1" yoffset="1" xadvance="13" />
-    <char id="176" x="70" y="41" width="6" height="6" xoffset="1" yoffset="4" xadvance="9" />
-    <char id="177" x="720" y="18" width="12" height="14" xoffset="1" yoffset="7" xadvance="13" />
-    <char id="178" x="16" y="41" width="7" height="8" xoffset="0" yoffset="4" xadvance="8" />
-    <char id="179" x="0" y="41" width="7" height="8" xoffset="0" yoffset="4" xadvance="8" />
-    <char id="180" x="101" y="41" width="4" height="3" xoffset="3" yoffset="4" xadvance="8" />
-    <char id="181" x="603" y="0" width="10" height="18" xoffset="1" yoffset="8" xadvance="12" />
-    <char id="182" x="378" y="0" width="12" height="21" xoffset="0" yoffset="4" xadvance="12" />
-    <char id="183" x="164" y="40" width="2" height="2" xoffset="3" yoffset="12" xadvance="8" />
-    <char id="184" x="95" y="41" width="5" height="4" xoffset="1" yoffset="21" xadvance="8" />
-    <char id="185" x="1017" y="18" width="5" height="8" xoffset="1" yoffset="4" xadvance="8" />
-    <char id="186" x="24" y="41" width="7" height="8" xoffset="1" yoffset="4" xadvance="9" />
-    <char id="187" x="963" y="18" width="9" height="10" xoffset="3" yoffset="10" xadvance="13" />
-    <char id="188" x="705" y="0" width="18" height="17" xoffset="1" yoffset="4" xadvance="19" />
-    <char id="189" x="780" y="0" width="17" height="17" xoffset="1" yoffset="4" xadvance="19" />
-    <char id="190" x="743" y="0" width="18" height="17" xoffset="0" yoffset="4" xadvance="19" />
-    <char id="191" x="625" y="0" width="10" height="18" xoffset="2" yoffset="8" xadvance="14" />
-    <char id="192" x="137" y="0" width="17" height="21" xoffset="-1" yoffset="0" xadvance="15" />
-    <char id="193" x="173" y="0" width="17" height="21" xoffset="-1" yoffset="0" xadvance="15" />
-    <char id="194" x="191" y="0" width="17" height="21" xoffset="-1" yoffset="0" xadvance="15" />
-    <char id="195" x="155" y="0" width="17" height="21" xoffset="-1" yoffset="0" xadvance="15" />
-    <char id="196" x="449" y="0" width="17" height="20" xoffset="-1" yoffset="1" xadvance="15" />
-    <char id="197" x="119" y="0" width="17" height="21" xoffset="-1" yoffset="0" xadvance="15" />
-    <char id="198" x="681" y="0" width="23" height="17" xoffset="-1" yoffset="4" xadvance="23" />
-    <char id="199" x="277" y="0" width="15" height="21" xoffset="1" yoffset="4" xadvance="17" />
-    <char id="200" x="404" y="0" width="12" height="21" xoffset="2" yoffset="0" xadvance="15" />
-    <char id="201" x="391" y="0" width="12" height="21" xoffset="2" yoffset="0" xadvance="15" />
-    <char id="202" x="417" y="0" width="12" height="21" xoffset="2" yoffset="0" xadvance="15" />
-    <char id="203" x="498" y="0" width="12" height="20" xoffset="2" yoffset="1" xadvance="15" />
-    <char id="204" x="444" y="0" width="4" height="21" xoffset="1" yoffset="0" xadvance="6" />
-    <char id="205" x="439" y="0" width="4" height="21" xoffset="1" yoffset="0" xadvance="6" />
-    <char id="206" x="430" y="0" width="8" height="21" xoffset="-1" yoffset="0" xadvance="6" />
-    <char id="207" x="523" y="0" width="6" height="20" xoffset="0" yoffset="1" xadvance="6" />
-    <char id="208" x="886" y="0" width="16" height="17" xoffset="0" yoffset="4" xadvance="17" />
-    <char id="209" x="364" y="0" width="13" height="21" xoffset="2" yoffset="0" xadvance="17" />
-    <char id="210" x="209" y="0" width="16" height="21" xoffset="1" yoffset="0" xadvance="18" />
-    <char id="211" x="260" y="0" width="16" height="21" xoffset="1" yoffset="0" xadvance="18" />
-    <char id="212" x="243" y="0" width="16" height="21" xoffset="1" yoffset="0" xadvance="18" />
-    <char id="213" x="226" y="0" width="16" height="21" xoffset="1" yoffset="0" xadvance="18" />
-    <char id="214" x="467" y="0" width="16" height="20" xoffset="1" yoffset="1" xadvance="18" />
-    <char id="215" x="994" y="18" width="9" height="9" xoffset="2" yoffset="8" xadvance="13" />
-    <char id="216" x="542" y="0" width="17" height="18" xoffset="1" yoffset="4" xadvance="18" />
-    <char id="217" x="350" y="0" width="13" height="21" xoffset="2" yoffset="0" xadvance="17" />
-    <char id="218" x="336" y="0" width="13" height="21" xoffset="2" yoffset="0" xadvance="17" />
-    <char id="219" x="322" y="0" width="13" height="21" xoffset="2" yoffset="0" xadvance="17" />
-    <char id="220" x="484" y="0" width="13" height="20" xoffset="2" yoffset="1" xadvance="17" />
-    <char id="221" x="293" y="0" width="14" height="21" xoffset="0" yoffset="0" xadvance="15" />
-    <char id="222" x="137" y="22" width="12" height="17" xoffset="2" yoffset="4" xadvance="15" />
-    <char id="223" x="150" y="22" width="12" height="17" xoffset="2" yoffset="4" xadvance="14" />
-    <char id="224" x="297" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="225" x="309" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="226" x="321" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="227" x="333" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="228" x="675" y="18" width="11" height="16" xoffset="1" yoffset="5" xadvance="13" />
-    <char id="229" x="530" y="0" width="11" height="19" xoffset="1" yoffset="2" xadvance="13" />
-    <char id="230" x="733" y="18" width="19" height="13" xoffset="1" yoffset="8" xadvance="20" />
-    <char id="231" x="488" y="21" width="10" height="17" xoffset="1" yoffset="8" xadvance="12" />
-    <char id="232" x="465" y="21" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="233" x="357" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="234" x="369" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="235" x="663" y="18" width="11" height="16" xoffset="1" yoffset="5" xadvance="13" />
-    <char id="236" x="627" y="19" width="4" height="17" xoffset="1" yoffset="4" xadvance="6" />
-    <char id="237" x="632" y="19" width="4" height="17" xoffset="1" yoffset="4" xadvance="6" />
-    <char id="238" x="586" y="19" width="8" height="17" xoffset="-1" yoffset="4" xadvance="6" />
-    <char id="239" x="710" y="18" width="6" height="16" xoffset="0" yoffset="5" xadvance="6" />
-    <char id="240" x="381" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="241" x="510" y="21" width="10" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="242" x="393" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="243" x="405" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="244" x="417" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="245" x="429" y="22" width="11" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="246" x="687" y="18" width="11" height="16" xoffset="1" yoffset="5" xadvance="13" />
-    <char id="247" x="1004" y="18" width="12" height="8" xoffset="1" yoffset="9" xadvance="13" />
-    <char id="248" x="649" y="19" width="13" height="16" xoffset="0" yoffset="6" xadvance="13" />
-    <char id="249" x="532" y="20" width="10" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="250" x="521" y="21" width="10" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="251" x="499" y="21" width="10" height="17" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="252" x="699" y="18" width="10" height="16" xoffset="1" yoffset="5" xadvance="13" />
-    <char id="253" x="22" y="0" width="13" height="22" xoffset="-1" yoffset="4" xadvance="12" />
-    <char id="254" x="36" y="0" width="11" height="22" xoffset="1" yoffset="4" xadvance="13" />
-    <char id="255" x="308" y="0" width="13" height="21" xoffset="-1" yoffset="5" xadvance="12" />
-  </chars>
-  <kernings count="70">
-    <kerning first="32" second="65" amount="-1" />
-    <kerning first="49" second="49" amount="-2" />
-    <kerning first="65" second="32" amount="-1" />
-    <kerning first="65" second="84" amount="-2" />
-    <kerning first="65" second="86" amount="-2" />
-    <kerning first="65" second="87" amount="-1" />
-    <kerning first="65" second="89" amount="-2" />
-    <kerning first="70" second="44" amount="-3" />
-    <kerning first="70" second="46" amount="-3" />
-    <kerning first="70" second="65" amount="-1" />
-    <kerning first="76" second="32" amount="-1" />
-    <kerning first="76" second="84" amount="-2" />
-    <kerning first="76" second="86" amount="-2" />
-    <kerning first="76" second="87" amount="-2" />
-    <kerning first="76" second="89" amount="-2" />
-    <kerning first="76" second="121" amount="-1" />
-    <kerning first="80" second="44" amount="-3" />
-    <kerning first="80" second="46" amount="-3" />
-    <kerning first="80" second="65" amount="-2" />
-    <kerning first="84" second="44" amount="-3" />
-    <kerning first="84" second="45" amount="-1" />
-    <kerning first="84" second="46" amount="-3" />
-    <kerning first="84" second="58" amount="-3" />
-    <kerning first="84" second="65" amount="-2" />
-    <kerning first="84" second="97" amount="-3" />
-    <kerning first="84" second="99" amount="-3" />
-    <kerning first="84" second="101" amount="-3" />
-    <kerning first="84" second="105" amount="-1" />
-    <kerning first="84" second="111" amount="-3" />
-    <kerning first="84" second="114" amount="-1" />
-    <kerning first="84" second="115" amount="-3" />
-    <kerning first="84" second="117" amount="-1" />
-    <kerning first="84" second="119" amount="-1" />
-    <kerning first="84" second="121" amount="-1" />
-    <kerning first="86" second="44" amount="-2" />
-    <kerning first="86" second="45" amount="-1" />
-    <kerning first="86" second="46" amount="-2" />
-    <kerning first="86" second="58" amount="-1" />
-    <kerning first="86" second="65" amount="-2" />
-    <kerning first="86" second="97" amount="-2" />
-    <kerning first="86" second="101" amount="-1" />
-    <kerning first="86" second="111" amount="-1" />
-    <kerning first="86" second="114" amount="-1" />
-    <kerning first="86" second="117" amount="-1" />
-    <kerning first="86" second="121" amount="-1" />
-    <kerning first="87" second="44" amount="-1" />
-    <kerning first="87" second="46" amount="-1" />
-    <kerning first="87" second="65" amount="-1" />
-    <kerning first="87" second="97" amount="-1" />
-    <kerning first="89" second="44" amount="-3" />
-    <kerning first="89" second="45" amount="-2" />
-    <kerning first="89" second="46" amount="-3" />
-    <kerning first="89" second="58" amount="-1" />
-    <kerning first="89" second="65" amount="-2" />
-    <kerning first="89" second="97" amount="-2" />
-    <kerning first="89" second="101" amount="-2" />
-    <kerning first="89" second="105" amount="-1" />
-    <kerning first="89" second="111" amount="-2" />
-    <kerning first="89" second="112" amount="-2" />
-    <kerning first="89" second="113" amount="-2" />
-    <kerning first="89" second="117" amount="-1" />
-    <kerning first="89" second="118" amount="-1" />
-    <kerning first="114" second="44" amount="-1" />
-    <kerning first="114" second="46" amount="-1" />
-    <kerning first="118" second="44" amount="-2" />
-    <kerning first="118" second="46" amount="-2" />
-    <kerning first="119" second="44" amount="-1" />
-    <kerning first="119" second="46" amount="-1" />
-    <kerning first="121" second="44" amount="-2" />
-    <kerning first="121" second="46" amount="-2" />
-  </kernings>
-</font>

BIN
Samples/assets/Arial_0.tga


+ 97 - 0
Samples/assets/LICENSE.txt

@@ -0,0 +1,97 @@
+The Noto Emoji font, located in the file 'NotoEmoji-Regular.ttf', is part of the Noto Project. See google.com/get/noto for more information. The font is licensed under the SIL Open Font License v1.1. Full license stated below.
+
+
+-----------------------------------------------------------
+
+This Font Software is licensed under the SIL Open Font License,
+Version 1.1.
+
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font
+creation efforts of academic and linguistic communities, and to
+provide a free and open framework in which fonts may be shared and
+improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply to
+any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software
+components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to,
+deleting, or substituting -- in part or in whole -- any of the
+components of the Original Version, by changing formats or by porting
+the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed,
+modify, redistribute, and sell modified and unmodified copies of the
+Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in
+Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the
+corresponding Copyright Holder. This restriction only applies to the
+primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created using
+the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.

BIN
Samples/assets/NotoEmoji-Regular.ttf


+ 0 - 28
Samples/assets/bitmapfont.rml

@@ -1,28 +0,0 @@
-<rml>
-	<head>
-		<title>Demo</title>
-		<link type="text/template" href="window.rml" />
-		<style>
-			body
-			{
-				width: 300px;
-				height: 225px;
-				font-family: Arial;
-				margin: auto;
-			}
-			
-			div#title_bar div#icon
-			{
-				display: none;
-			}
-			
-			div#content
-			{
-				text-align: left;
-			}
-		</style>
-	</head>
-	<body template="window">
-		This is a bitmap font<br/>sample.
-	</body>
-</rml>

+ 758 - 0
Samples/basic/bitmapfont/data/Comfortaa_Regular_22.fnt

@@ -0,0 +1,758 @@
+<?xml version="1.0"?>
+<font>
+  <info face="Comfortaa" size="22" bold="0" italic="0" charset="" unicode="1" stretchH="100" smooth="1" aa="2" padding="0,0,0,0" spacing="2,2" outline="0"/>
+  <common lineHeight="22" base="18" scaleW="256" scaleH="128" pages="1" packed="0" alphaChnl="0" redChnl="4" greenChnl="4" blueChnl="4"/>
+  <pages>
+    <page id="0" file="Comfortaa_Regular_22.tga" />
+  </pages>
+  <chars count="191">
+    <char id="32" x="253" y="67" width="1" height="1" xoffset="0" yoffset="0" xadvance="4" page="0" chnl="15" />
+    <char id="33" x="159" y="86" width="3" height="14" xoffset="0" yoffset="3" xadvance="4" page="0" chnl="15" />
+    <char id="34" x="227" y="113" width="4" height="5" xoffset="0" yoffset="2" xadvance="5" page="0" chnl="15" />
+    <char id="35" x="176" y="54" width="10" height="14" xoffset="1" yoffset="3" xadvance="12" page="0" chnl="15" />
+    <char id="36" x="182" y="0" width="8" height="18" xoffset="0" yoffset="1" xadvance="9" page="0" chnl="15" />
+    <char id="37" x="239" y="19" width="14" height="14" xoffset="0" yoffset="3" xadvance="15" page="0" chnl="15" />
+    <char id="38" x="126" y="39" width="12" height="14" xoffset="0" yoffset="3" xadvance="13" page="0" chnl="15" />
+    <char id="39" x="251" y="110" width="2" height="5" xoffset="0" yoffset="2" xadvance="3" page="0" chnl="15" />
+    <char id="40" x="0" y="0" width="4" height="20" xoffset="2" yoffset="2" xadvance="7" page="0" chnl="15" />
+    <char id="41" x="6" y="0" width="4" height="20" xoffset="0" yoffset="2" xadvance="7" page="0" chnl="15" />
+    <char id="42" x="205" y="113" width="6" height="6" xoffset="2" yoffset="2" xadvance="9" page="0" chnl="15" />
+    <char id="43" x="102" y="115" width="8" height="8" xoffset="1" yoffset="6" xadvance="9" page="0" chnl="15" />
+    <char id="44" x="245" y="111" width="4" height="5" xoffset="0" yoffset="14" xadvance="5" page="0" chnl="15" />
+    <char id="45" x="35" y="119" width="6" height="3" xoffset="0" yoffset="11" xadvance="6" page="0" chnl="15" />
+    <char id="46" x="51" y="118" width="3" height="3" xoffset="1" yoffset="14" xadvance="5" page="0" chnl="15" />
+    <char id="47" x="205" y="20" width="7" height="16" xoffset="0" yoffset="3" xadvance="7" page="0" chnl="15" />
+    <char id="48" x="85" y="87" width="8" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="49" x="248" y="51" width="4" height="14" xoffset="0" yoffset="3" xadvance="5" page="0" chnl="15" />
+    <char id="50" x="209" y="70" width="9" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="51" x="65" y="87" width="8" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="52" x="65" y="55" width="11" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="53" x="220" y="70" width="9" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="54" x="75" y="87" width="8" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="55" x="143" y="70" width="9" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="56" x="105" y="87" width="8" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="57" x="95" y="87" width="8" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="58" x="250" y="98" width="3" height="10" xoffset="1" yoffset="8" xadvance="5" page="0" chnl="15" />
+    <char id="59" x="47" y="105" width="3" height="11" xoffset="1" yoffset="8" xadvance="5" page="0" chnl="15" />
+    <char id="60" x="72" y="115" width="8" height="10" xoffset="1" yoffset="7" xadvance="9" page="0" chnl="15" />
+    <char id="61" x="185" y="113" width="8" height="6" xoffset="1" yoffset="9" xadvance="9" page="0" chnl="15" />
+    <char id="62" x="240" y="99" width="8" height="10" xoffset="1" yoffset="6" xadvance="9" page="0" chnl="15" />
+    <char id="63" x="231" y="68" width="9" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="64" x="35" y="0" width="18" height="18" xoffset="0" yoffset="2" xadvance="18" page="0" chnl="15" />
+    <char id="65" x="78" y="55" width="11" height="14" xoffset="0" yoffset="3" xadvance="11" page="0" chnl="15" />
+    <char id="66" x="11" y="89" width="9" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="67" x="154" y="38" width="12" height="14" xoffset="0" yoffset="3" xadvance="12" page="0" chnl="15" />
+    <char id="68" x="196" y="38" width="11" height="14" xoffset="0" yoffset="3" xadvance="11" page="0" chnl="15" />
+    <char id="69" x="108" y="71" width="10" height="14" xoffset="0" yoffset="3" xadvance="10" page="0" chnl="15" />
+    <char id="70" x="96" y="71" width="10" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="71" x="140" y="38" width="12" height="14" xoffset="0" yoffset="3" xadvance="12" page="0" chnl="15" />
+    <char id="72" x="12" y="73" width="10" height="14" xoffset="0" yoffset="3" xadvance="11" page="0" chnl="15" />
+    <char id="73" x="153" y="86" width="4" height="14" xoffset="0" yoffset="3" xadvance="5" page="0" chnl="15" />
+    <char id="74" x="22" y="89" width="9" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="75" x="104" y="55" width="10" height="14" xoffset="0" yoffset="3" xadvance="10" page="0" chnl="15" />
+    <char id="76" x="33" y="89" width="9" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="77" x="96" y="39" width="13" height="14" xoffset="0" yoffset="3" xadvance="14" page="0" chnl="15" />
+    <char id="78" x="39" y="56" width="11" height="14" xoffset="0" yoffset="3" xadvance="12" page="0" chnl="15" />
+    <char id="79" x="80" y="39" width="14" height="14" xoffset="0" yoffset="3" xadvance="15" page="0" chnl="15" />
+    <char id="80" x="115" y="87" width="8" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="81" x="48" y="39" width="14" height="14" xoffset="0" yoffset="3" xadvance="15" page="0" chnl="15" />
+    <char id="82" x="44" y="89" width="9" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="83" x="125" y="87" width="8" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="84" x="209" y="38" width="11" height="14" xoffset="0" yoffset="3" xadvance="11" page="0" chnl="15" />
+    <char id="85" x="0" y="73" width="10" height="14" xoffset="0" yoffset="3" xadvance="11" page="0" chnl="15" />
+    <char id="86" x="222" y="36" width="11" height="14" xoffset="0" yoffset="3" xadvance="11" page="0" chnl="15" />
+    <char id="87" x="221" y="20" width="16" height="14" xoffset="0" yoffset="3" xadvance="16" page="0" chnl="15" />
+    <char id="88" x="235" y="36" width="11" height="14" xoffset="0" yoffset="3" xadvance="12" page="0" chnl="15" />
+    <char id="89" x="0" y="57" width="11" height="14" xoffset="0" yoffset="3" xadvance="10" page="0" chnl="15" />
+    <char id="90" x="13" y="57" width="11" height="14" xoffset="0" yoffset="3" xadvance="12" page="0" chnl="15" />
+    <char id="91" x="20" y="0" width="6" height="19" xoffset="2" yoffset="2" xadvance="7" page="0" chnl="15" />
+    <char id="92" x="196" y="20" width="7" height="16" xoffset="0" yoffset="2" xadvance="6" page="0" chnl="15" />
+    <char id="93" x="28" y="0" width="5" height="19" xoffset="0" yoffset="2" xadvance="7" page="0" chnl="15" />
+    <char id="94" x="129" y="115" width="7" height="7" xoffset="0" yoffset="3" xadvance="8" page="0" chnl="15" />
+    <char id="95" x="56" y="117" width="10" height="2" xoffset="0" yoffset="17" xadvance="9" page="0" chnl="15" />
+    <char id="96" x="239" y="113" width="4" height="5" xoffset="1" yoffset="4" xadvance="7" page="0" chnl="15" />
+    <char id="97" x="139" y="103" width="10" height="10" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="98" x="26" y="57" width="11" height="14" xoffset="0" yoffset="3" xadvance="11" page="0" chnl="15" />
+    <char id="99" x="187" y="101" width="9" height="10" xoffset="0" yoffset="7" xadvance="9" page="0" chnl="15" />
+    <char id="100" x="52" y="55" width="11" height="14" xoffset="0" yoffset="3" xadvance="11" page="0" chnl="15" />
+    <char id="101" x="103" y="103" width="10" height="10" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="102" x="135" y="87" width="7" height="14" xoffset="0" yoffset="3" xadvance="8" page="0" chnl="15" />
+    <char id="103" x="236" y="52" width="10" height="14" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="104" x="116" y="55" width="10" height="14" xoffset="0" yoffset="3" xadvance="11" page="0" chnl="15" />
+    <char id="105" x="237" y="84" width="2" height="13" xoffset="0" yoffset="5" xadvance="4" page="0" chnl="15" />
+    <char id="106" x="130" y="20" width="5" height="17" xoffset="0" yoffset="5" xadvance="6" page="0" chnl="15" />
+    <char id="107" x="132" y="71" width="9" height="14" xoffset="0" yoffset="3" xadvance="10" page="0" chnl="15" />
+    <char id="108" x="248" y="35" width="4" height="14" xoffset="0" yoffset="4" xadvance="4" page="0" chnl="15" />
+    <char id="109" x="72" y="103" width="15" height="10" xoffset="0" yoffset="7" xadvance="16" page="0" chnl="15" />
+    <char id="110" x="115" y="103" width="10" height="10" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="111" x="127" y="103" width="10" height="10" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="112" x="212" y="54" width="10" height="14" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="113" x="224" y="52" width="10" height="14" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="114" x="230" y="101" width="8" height="10" xoffset="0" yoffset="7" xadvance="8" page="0" chnl="15" />
+    <char id="115" x="82" y="115" width="8" height="10" xoffset="0" yoffset="7" xadvance="9" page="0" chnl="15" />
+    <char id="116" x="144" y="86" width="7" height="14" xoffset="0" yoffset="4" xadvance="6" page="0" chnl="15" />
+    <char id="117" x="151" y="102" width="10" height="10" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="118" x="163" y="102" width="10" height="10" xoffset="0" yoffset="7" xadvance="10" page="0" chnl="15" />
+    <char id="119" x="89" y="103" width="12" height="10" xoffset="0" yoffset="7" xadvance="13" page="0" chnl="15" />
+    <char id="120" x="209" y="101" width="9" height="10" xoffset="0" yoffset="7" xadvance="9" page="0" chnl="15" />
+    <char id="121" x="199" y="86" width="8" height="13" xoffset="0" yoffset="7" xadvance="8" page="0" chnl="15" />
+    <char id="122" x="198" y="101" width="9" height="10" xoffset="0" yoffset="7" xadvance="9" page="0" chnl="15" />
+    <char id="123" x="210" y="0" width="6" height="18" xoffset="2" yoffset="2" xadvance="9" page="0" chnl="15" />
+    <char id="124" x="16" y="0" width="2" height="20" xoffset="3" yoffset="2" xadvance="9" page="0" chnl="15" />
+    <char id="125" x="192" y="0" width="7" height="18" xoffset="0" yoffset="2" xadvance="9" page="0" chnl="15" />
+    <char id="126" x="0" y="119" width="7" height="4" xoffset="1" yoffset="9" xadvance="9" page="0" chnl="15" />
+    <char id="160" x="253" y="0" width="1" height="1" xoffset="0" yoffset="0" xadvance="4" page="0" chnl="15" />
+    <char id="161" x="232" y="84" width="3" height="13" xoffset="1" yoffset="4" xadvance="6" page="0" chnl="15" />
+    <char id="162" x="175" y="20" width="9" height="16" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="163" x="55" y="88" width="8" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="164" x="138" y="115" width="7" height="7" xoffset="1" yoffset="7" xadvance="9" page="0" chnl="15" />
+    <char id="165" x="241" y="84" width="11" height="12" xoffset="0" yoffset="5" xadvance="11" page="0" chnl="15" />
+    <char id="166" x="12" y="0" width="2" height="20" xoffset="2" yoffset="2" xadvance="7" page="0" chnl="15" />
+    <char id="167" x="201" y="0" width="7" height="18" xoffset="1" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="168" x="26" y="119" width="7" height="3" xoffset="1" yoffset="5" xadvance="9" page="0" chnl="15" />
+    <char id="169" x="0" y="41" width="14" height="14" xoffset="0" yoffset="3" xadvance="15" page="0" chnl="15" />
+    <char id="170" x="213" y="113" width="6" height="6" xoffset="0" yoffset="4" xadvance="6" page="0" chnl="15" />
+    <char id="171" x="163" y="114" width="6" height="7" xoffset="2" yoffset="9" xadvance="9" page="0" chnl="15" />
+    <char id="172" x="195" y="113" width="8" height="6" xoffset="0" yoffset="10" xadvance="9" page="0" chnl="15" />
+    <char id="173" x="43" y="119" width="6" height="3" xoffset="0" yoffset="11" xadvance="6" page="0" chnl="15" />
+    <char id="174" x="16" y="41" width="14" height="14" xoffset="0" yoffset="3" xadvance="15" page="0" chnl="15" />
+    <char id="175" x="14" y="119" width="10" height="3" xoffset="-1" yoffset="0" xadvance="7" page="0" chnl="15" />
+    <char id="176" x="147" y="115" width="6" height="7" xoffset="0" yoffset="3" xadvance="6" page="0" chnl="15" />
+    <char id="177" x="220" y="101" width="8" height="10" xoffset="1" yoffset="6" xadvance="9" page="0" chnl="15" />
+    <char id="178" x="112" y="115" width="5" height="8" xoffset="2" yoffset="2" xadvance="9" page="0" chnl="15" />
+    <char id="179" x="119" y="115" width="4" height="8" xoffset="2" yoffset="2" xadvance="9" page="0" chnl="15" />
+    <char id="180" x="233" y="113" width="4" height="5" xoffset="2" yoffset="4" xadvance="8" page="0" chnl="15" />
+    <char id="181" x="36" y="73" width="10" height="14" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="182" x="154" y="70" width="9" height="14" xoffset="0" yoffset="3" xadvance="9" page="0" chnl="15" />
+    <char id="183" x="9" y="119" width="3" height="4" xoffset="1" yoffset="10" xadvance="4" page="0" chnl="15" />
+    <char id="184" x="221" y="113" width="4" height="5" xoffset="3" yoffset="16" xadvance="9" page="0" chnl="15" />
+    <char id="185" x="125" y="115" width="2" height="8" xoffset="3" yoffset="2" xadvance="9" page="0" chnl="15" />
+    <char id="186" x="179" y="113" width="4" height="7" xoffset="1" yoffset="2" xadvance="6" page="0" chnl="15" />
+    <char id="187" x="171" y="114" width="6" height="7" xoffset="1" yoffset="9" xadvance="9" page="0" chnl="15" />
+    <char id="188" x="182" y="38" width="12" height="14" xoffset="1" yoffset="3" xadvance="14" page="0" chnl="15" />
+    <char id="189" x="168" y="38" width="12" height="14" xoffset="0" yoffset="3" xadvance="14" page="0" chnl="15" />
+    <char id="190" x="111" y="39" width="13" height="14" xoffset="0" yoffset="3" xadvance="14" page="0" chnl="15" />
+    <char id="191" x="165" y="70" width="9" height="14" xoffset="0" yoffset="7" xadvance="9" page="0" chnl="15" />
+    <char id="192" x="58" y="20" width="11" height="17" xoffset="0" yoffset="0" xadvance="11" page="0" chnl="15" />
+    <char id="193" x="71" y="20" width="11" height="17" xoffset="0" yoffset="0" xadvance="11" page="0" chnl="15" />
+    <char id="194" x="32" y="21" width="11" height="17" xoffset="0" yoffset="0" xadvance="11" page="0" chnl="15" />
+    <char id="195" x="150" y="20" width="11" height="16" xoffset="0" yoffset="1" xadvance="11" page="0" chnl="15" />
+    <char id="196" x="137" y="20" width="11" height="16" xoffset="0" yoffset="1" xadvance="11" page="0" chnl="15" />
+    <char id="197" x="87" y="0" width="11" height="18" xoffset="0" yoffset="0" xadvance="11" page="0" chnl="15" />
+    <char id="198" x="32" y="40" width="14" height="14" xoffset="0" yoffset="3" xadvance="14" page="0" chnl="15" />
+    <char id="199" x="100" y="0" width="11" height="18" xoffset="0" yoffset="3" xadvance="13" page="0" chnl="15" />
+    <char id="200" x="160" y="0" width="9" height="18" xoffset="0" yoffset="0" xadvance="9" page="0" chnl="15" />
+    <char id="201" x="149" y="0" width="9" height="18" xoffset="0" yoffset="0" xadvance="9" page="0" chnl="15" />
+    <char id="202" x="108" y="20" width="9" height="17" xoffset="0" yoffset="0" xadvance="9" page="0" chnl="15" />
+    <char id="203" x="119" y="20" width="9" height="17" xoffset="0" yoffset="1" xadvance="9" page="0" chnl="15" />
+    <char id="204" x="218" y="0" width="4" height="18" xoffset="1" yoffset="0" xadvance="6" page="0" chnl="15" />
+    <char id="205" x="224" y="0" width="4" height="18" xoffset="1" yoffset="0" xadvance="6" page="0" chnl="15" />
+    <char id="206" x="246" y="0" width="5" height="17" xoffset="0" yoffset="0" xadvance="6" page="0" chnl="15" />
+    <char id="207" x="214" y="20" width="5" height="16" xoffset="0" yoffset="1" xadvance="6" page="0" chnl="15" />
+    <char id="208" x="91" y="55" width="11" height="14" xoffset="0" yoffset="3" xadvance="12" page="0" chnl="15" />
+    <char id="209" x="45" y="20" width="11" height="17" xoffset="0" yoffset="1" xadvance="12" page="0" chnl="15" />
+    <char id="210" x="55" y="0" width="14" height="18" xoffset="0" yoffset="0" xadvance="14" page="0" chnl="15" />
+    <char id="211" x="71" y="0" width="14" height="18" xoffset="0" yoffset="0" xadvance="14" page="0" chnl="15" />
+    <char id="212" x="230" y="0" width="14" height="17" xoffset="0" yoffset="0" xadvance="14" page="0" chnl="15" />
+    <char id="213" x="0" y="22" width="14" height="17" xoffset="0" yoffset="0" xadvance="14" page="0" chnl="15" />
+    <char id="214" x="16" y="22" width="14" height="17" xoffset="0" yoffset="1" xadvance="14" page="0" chnl="15" />
+    <char id="215" x="155" y="114" width="6" height="7" xoffset="2" yoffset="8" xadvance="9" page="0" chnl="15" />
+    <char id="216" x="64" y="39" width="14" height="14" xoffset="0" yoffset="3" xadvance="15" page="0" chnl="15" />
+    <char id="217" x="113" y="0" width="10" height="18" xoffset="0" yoffset="0" xadvance="10" page="0" chnl="15" />
+    <char id="218" x="137" y="0" width="10" height="18" xoffset="0" yoffset="0" xadvance="10" page="0" chnl="15" />
+    <char id="219" x="96" y="20" width="10" height="17" xoffset="0" yoffset="0" xadvance="10" page="0" chnl="15" />
+    <char id="220" x="163" y="20" width="10" height="16" xoffset="0" yoffset="1" xadvance="10" page="0" chnl="15" />
+    <char id="221" x="84" y="20" width="10" height="17" xoffset="0" yoffset="0" xadvance="10" page="0" chnl="15" />
+    <char id="222" x="176" y="70" width="9" height="14" xoffset="0" yoffset="3" xadvance="10" page="0" chnl="15" />
+    <char id="223" x="187" y="70" width="9" height="14" xoffset="0" yoffset="3" xadvance="10" page="0" chnl="15" />
+    <char id="224" x="128" y="55" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="225" x="140" y="54" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="226" x="24" y="73" width="10" height="14" xoffset="0" yoffset="4" xadvance="11" page="0" chnl="15" />
+    <char id="227" x="164" y="86" width="10" height="13" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="228" x="0" y="105" width="10" height="12" xoffset="0" yoffset="5" xadvance="10" page="0" chnl="15" />
+    <char id="229" x="152" y="54" width="10" height="14" xoffset="0" yoffset="3" xadvance="10" page="0" chnl="15" />
+    <char id="230" x="52" y="105" width="18" height="10" xoffset="0" yoffset="7" xadvance="18" page="0" chnl="15" />
+    <char id="231" x="198" y="70" width="9" height="14" xoffset="0" yoffset="7" xadvance="9" page="0" chnl="15" />
+    <char id="232" x="120" y="71" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="233" x="164" y="54" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="234" x="188" y="54" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="235" x="12" y="105" width="10" height="12" xoffset="0" yoffset="5" xadvance="10" page="0" chnl="15" />
+    <char id="236" x="222" y="86" width="3" height="13" xoffset="0" yoffset="4" xadvance="5" page="0" chnl="15" />
+    <char id="237" x="227" y="86" width="3" height="13" xoffset="1" yoffset="4" xadvance="5" page="0" chnl="15" />
+    <char id="238" x="216" y="86" width="4" height="13" xoffset="0" yoffset="4" xadvance="5" page="0" chnl="15" />
+    <char id="239" x="209" y="86" width="5" height="13" xoffset="0" yoffset="5" xadvance="5" page="0" chnl="15" />
+    <char id="240" x="200" y="54" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="241" x="188" y="86" width="9" height="13" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="242" x="48" y="72" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="243" x="60" y="71" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="244" x="72" y="71" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="245" x="176" y="86" width="10" height="13" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="246" x="24" y="105" width="10" height="12" xoffset="0" yoffset="5" xadvance="10" page="0" chnl="15" />
+    <char id="247" x="92" y="115" width="8" height="9" xoffset="1" yoffset="6" xadvance="9" page="0" chnl="15" />
+    <char id="248" x="175" y="101" width="10" height="10" xoffset="0" yoffset="7" xadvance="11" page="0" chnl="15" />
+    <char id="249" x="242" y="68" width="9" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="250" x="0" y="89" width="9" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="251" x="84" y="71" width="10" height="14" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="252" x="36" y="105" width="9" height="12" xoffset="0" yoffset="5" xadvance="10" page="0" chnl="15" />
+    <char id="253" x="171" y="0" width="9" height="18" xoffset="0" yoffset="4" xadvance="9" page="0" chnl="15" />
+    <char id="254" x="125" y="0" width="10" height="18" xoffset="0" yoffset="4" xadvance="10" page="0" chnl="15" />
+    <char id="255" x="186" y="20" width="8" height="16" xoffset="0" yoffset="5" xadvance="9" page="0" chnl="15" />
+  </chars>
+  <kernings count="555">
+    <kerning first="65" second="84" amount="-1" />
+    <kerning first="65" second="86" amount="-2" />
+    <kerning first="65" second="87" amount="-1" />
+    <kerning first="65" second="89" amount="-1" />
+    <kerning first="65" second="106" amount="-2" />
+    <kerning first="65" second="116" amount="-1" />
+    <kerning first="65" second="221" amount="-1" />
+    <kerning first="66" second="106" amount="-2" />
+    <kerning first="67" second="102" amount="-1" />
+    <kerning first="67" second="106" amount="-2" />
+    <kerning first="67" second="118" amount="-1" />
+    <kerning first="67" second="121" amount="-1" />
+    <kerning first="67" second="253" amount="-1" />
+    <kerning first="255" second="221" amount="-1" />
+    <kerning first="68" second="84" amount="-1" />
+    <kerning first="68" second="106" amount="-2" />
+    <kerning first="69" second="106" amount="-2" />
+    <kerning first="69" second="118" amount="-1" />
+    <kerning first="69" second="121" amount="-1" />
+    <kerning first="69" second="253" amount="-1" />
+    <kerning first="70" second="65" amount="-2" />
+    <kerning first="70" second="74" amount="-1" />
+    <kerning first="70" second="106" amount="-2" />
+    <kerning first="255" second="198" amount="-1" />
+    <kerning first="70" second="192" amount="-2" />
+    <kerning first="70" second="193" amount="-1" />
+    <kerning first="70" second="194" amount="-2" />
+    <kerning first="70" second="195" amount="-1" />
+    <kerning first="70" second="196" amount="-2" />
+    <kerning first="70" second="197" amount="-2" />
+    <kerning first="70" second="198" amount="-2" />
+    <kerning first="71" second="106" amount="-2" />
+    <kerning first="72" second="106" amount="-1" />
+    <kerning first="73" second="106" amount="-2" />
+    <kerning first="74" second="106" amount="-1" />
+    <kerning first="75" second="106" amount="-1" />
+    <kerning first="75" second="118" amount="-1" />
+    <kerning first="255" second="197" amount="-1" />
+    <kerning first="75" second="199" amount="-1" />
+    <kerning first="75" second="253" amount="-1" />
+    <kerning first="75" second="255" amount="-1" />
+    <kerning first="76" second="67" amount="-1" />
+    <kerning first="76" second="71" amount="-1" />
+    <kerning first="76" second="79" amount="-1" />
+    <kerning first="76" second="81" amount="-1" />
+    <kerning first="76" second="84" amount="-3" />
+    <kerning first="76" second="86" amount="-2" />
+    <kerning first="76" second="87" amount="-2" />
+    <kerning first="76" second="89" amount="-3" />
+    <kerning first="76" second="106" amount="-2" />
+    <kerning first="76" second="118" amount="-2" />
+    <kerning first="76" second="121" amount="-1" />
+    <kerning first="76" second="199" amount="-1" />
+    <kerning first="76" second="210" amount="-1" />
+    <kerning first="76" second="211" amount="-1" />
+    <kerning first="76" second="212" amount="-2" />
+    <kerning first="76" second="213" amount="-1" />
+    <kerning first="76" second="214" amount="-2" />
+    <kerning first="76" second="221" amount="-2" />
+    <kerning first="76" second="253" amount="-1" />
+    <kerning first="76" second="255" amount="-1" />
+    <kerning first="77" second="106" amount="-2" />
+    <kerning first="78" second="106" amount="-1" />
+    <kerning first="79" second="84" amount="-1" />
+    <kerning first="79" second="106" amount="-2" />
+    <kerning first="80" second="65" amount="-2" />
+    <kerning first="80" second="74" amount="-1" />
+    <kerning first="80" second="106" amount="-2" />
+    <kerning first="80" second="192" amount="-2" />
+    <kerning first="80" second="193" amount="-2" />
+    <kerning first="80" second="194" amount="-2" />
+    <kerning first="80" second="195" amount="-2" />
+    <kerning first="80" second="196" amount="-2" />
+    <kerning first="80" second="197" amount="-2" />
+    <kerning first="80" second="198" amount="-3" />
+    <kerning first="81" second="84" amount="-1" />
+    <kerning first="81" second="106" amount="-1" />
+    <kerning first="82" second="106" amount="-1" />
+    <kerning first="83" second="106" amount="-1" />
+    <kerning first="84" second="65" amount="-3" />
+    <kerning first="84" second="67" amount="-2" />
+    <kerning first="84" second="71" amount="-1" />
+    <kerning first="84" second="74" amount="-2" />
+    <kerning first="84" second="79" amount="-1" />
+    <kerning first="84" second="81" amount="-1" />
+    <kerning first="84" second="97" amount="-2" />
+    <kerning first="84" second="99" amount="-3" />
+    <kerning first="84" second="100" amount="-2" />
+    <kerning first="84" second="101" amount="-2" />
+    <kerning first="84" second="102" amount="-2" />
+    <kerning first="84" second="103" amount="-2" />
+    <kerning first="84" second="106" amount="-2" />
+    <kerning first="84" second="109" amount="-2" />
+    <kerning first="84" second="110" amount="-2" />
+    <kerning first="84" second="111" amount="-2" />
+    <kerning first="84" second="112" amount="-2" />
+    <kerning first="84" second="113" amount="-2" />
+    <kerning first="84" second="114" amount="-1" />
+    <kerning first="84" second="115" amount="-1" />
+    <kerning first="84" second="117" amount="-1" />
+    <kerning first="84" second="118" amount="-1" />
+    <kerning first="84" second="119" amount="-1" />
+    <kerning first="84" second="120" amount="-1" />
+    <kerning first="84" second="121" amount="-1" />
+    <kerning first="84" second="122" amount="-1" />
+    <kerning first="84" second="192" amount="-1" />
+    <kerning first="84" second="193" amount="-1" />
+    <kerning first="84" second="194" amount="-1" />
+    <kerning first="84" second="195" amount="-2" />
+    <kerning first="84" second="196" amount="-1" />
+    <kerning first="84" second="197" amount="-2" />
+    <kerning first="84" second="198" amount="-2" />
+    <kerning first="84" second="199" amount="-1" />
+    <kerning first="84" second="210" amount="-1" />
+    <kerning first="84" second="211" amount="-1" />
+    <kerning first="84" second="212" amount="-1" />
+    <kerning first="84" second="213" amount="-1" />
+    <kerning first="84" second="214" amount="-1" />
+    <kerning first="84" second="216" amount="-1" />
+    <kerning first="84" second="224" amount="-2" />
+    <kerning first="84" second="225" amount="-2" />
+    <kerning first="84" second="226" amount="-1" />
+    <kerning first="84" second="228" amount="-2" />
+    <kerning first="84" second="229" amount="-1" />
+    <kerning first="84" second="230" amount="-2" />
+    <kerning first="84" second="231" amount="-2" />
+    <kerning first="84" second="232" amount="-2" />
+    <kerning first="84" second="233" amount="-2" />
+    <kerning first="84" second="234" amount="-1" />
+    <kerning first="84" second="235" amount="-2" />
+    <kerning first="255" second="196" amount="-1" />
+    <kerning first="84" second="240" amount="-1" />
+    <kerning first="84" second="242" amount="-1" />
+    <kerning first="84" second="243" amount="-1" />
+    <kerning first="84" second="244" amount="-1" />
+    <kerning first="84" second="246" amount="-1" />
+    <kerning first="84" second="248" amount="-1" />
+    <kerning first="84" second="249" amount="-1" />
+    <kerning first="84" second="250" amount="-1" />
+    <kerning first="84" second="251" amount="-1" />
+    <kerning first="84" second="252" amount="-1" />
+    <kerning first="84" second="253" amount="-1" />
+    <kerning first="84" second="255" amount="-1" />
+    <kerning first="85" second="106" amount="-2" />
+    <kerning first="86" second="65" amount="-2" />
+    <kerning first="86" second="74" amount="-2" />
+    <kerning first="86" second="106" amount="-2" />
+    <kerning first="86" second="192" amount="-2" />
+    <kerning first="86" second="193" amount="-2" />
+    <kerning first="86" second="194" amount="-2" />
+    <kerning first="86" second="195" amount="-2" />
+    <kerning first="86" second="196" amount="-2" />
+    <kerning first="86" second="197" amount="-2" />
+    <kerning first="86" second="198" amount="-2" />
+    <kerning first="86" second="231" amount="-1" />
+    <kerning first="87" second="65" amount="-1" />
+    <kerning first="87" second="106" amount="-2" />
+    <kerning first="87" second="192" amount="-1" />
+    <kerning first="87" second="193" amount="-1" />
+    <kerning first="87" second="194" amount="-2" />
+    <kerning first="87" second="195" amount="-1" />
+    <kerning first="87" second="196" amount="-1" />
+    <kerning first="87" second="197" amount="-2" />
+    <kerning first="87" second="198" amount="-1" />
+    <kerning first="88" second="71" amount="-1" />
+    <kerning first="88" second="106" amount="-1" />
+    <kerning first="88" second="121" amount="-1" />
+    <kerning first="88" second="199" amount="-1" />
+    <kerning first="88" second="210" amount="-1" />
+    <kerning first="88" second="212" amount="-1" />
+    <kerning first="88" second="213" amount="-1" />
+    <kerning first="88" second="253" amount="-1" />
+    <kerning first="88" second="255" amount="-1" />
+    <kerning first="89" second="65" amount="-2" />
+    <kerning first="89" second="74" amount="-2" />
+    <kerning first="89" second="97" amount="-1" />
+    <kerning first="89" second="99" amount="-1" />
+    <kerning first="89" second="100" amount="-1" />
+    <kerning first="89" second="101" amount="-1" />
+    <kerning first="89" second="103" amount="-1" />
+    <kerning first="89" second="106" amount="-2" />
+    <kerning first="89" second="111" amount="-2" />
+    <kerning first="89" second="112" amount="-1" />
+    <kerning first="89" second="113" amount="-2" />
+    <kerning first="89" second="115" amount="-1" />
+    <kerning first="89" second="192" amount="-2" />
+    <kerning first="89" second="193" amount="-1" />
+    <kerning first="89" second="194" amount="-1" />
+    <kerning first="89" second="195" amount="-1" />
+    <kerning first="89" second="196" amount="-1" />
+    <kerning first="89" second="197" amount="-1" />
+    <kerning first="89" second="198" amount="-1" />
+    <kerning first="89" second="224" amount="-1" />
+    <kerning first="89" second="225" amount="-1" />
+    <kerning first="89" second="226" amount="-1" />
+    <kerning first="89" second="228" amount="-1" />
+    <kerning first="89" second="229" amount="-1" />
+    <kerning first="89" second="230" amount="-1" />
+    <kerning first="89" second="231" amount="-1" />
+    <kerning first="89" second="232" amount="-1" />
+    <kerning first="89" second="233" amount="-1" />
+    <kerning first="89" second="234" amount="-1" />
+    <kerning first="89" second="235" amount="-1" />
+    <kerning first="89" second="240" amount="-1" />
+    <kerning first="89" second="242" amount="-1" />
+    <kerning first="89" second="243" amount="-1" />
+    <kerning first="89" second="244" amount="-1" />
+    <kerning first="89" second="246" amount="-1" />
+    <kerning first="89" second="248" amount="-1" />
+    <kerning first="90" second="106" amount="-1" />
+    <kerning first="255" second="195" amount="-1" />
+    <kerning first="97" second="84" amount="-3" />
+    <kerning first="97" second="89" amount="-3" />
+    <kerning first="97" second="106" amount="-2" />
+    <kerning first="97" second="221" amount="-3" />
+    <kerning first="98" second="84" amount="-2" />
+    <kerning first="98" second="86" amount="-1" />
+    <kerning first="98" second="89" amount="-3" />
+    <kerning first="98" second="106" amount="-2" />
+    <kerning first="98" second="221" amount="-2" />
+    <kerning first="99" second="84" amount="-2" />
+    <kerning first="99" second="89" amount="-1" />
+    <kerning first="99" second="106" amount="-1" />
+    <kerning first="99" second="221" amount="-1" />
+    <kerning first="100" second="106" amount="-1" />
+    <kerning first="101" second="84" amount="-3" />
+    <kerning first="101" second="89" amount="-2" />
+    <kerning first="101" second="106" amount="-2" />
+    <kerning first="101" second="221" amount="-2" />
+    <kerning first="102" second="65" amount="-1" />
+    <kerning first="102" second="74" amount="-1" />
+    <kerning first="102" second="106" amount="-2" />
+    <kerning first="102" second="192" amount="-1" />
+    <kerning first="255" second="194" amount="-1" />
+    <kerning first="255" second="193" amount="-1" />
+    <kerning first="255" second="192" amount="-1" />
+    <kerning first="255" second="106" amount="-2" />
+    <kerning first="255" second="90" amount="-1" />
+    <kerning first="102" second="198" amount="-1" />
+    <kerning first="103" second="84" amount="-2" />
+    <kerning first="103" second="89" amount="-2" />
+    <kerning first="103" second="221" amount="-2" />
+    <kerning first="104" second="84" amount="-3" />
+    <kerning first="104" second="89" amount="-2" />
+    <kerning first="104" second="106" amount="-2" />
+    <kerning first="104" second="221" amount="-2" />
+    <kerning first="105" second="106" amount="-1" />
+    <kerning first="107" second="84" amount="-2" />
+    <kerning first="107" second="106" amount="-1" />
+    <kerning first="108" second="106" amount="-1" />
+    <kerning first="109" second="84" amount="-2" />
+    <kerning first="109" second="89" amount="-2" />
+    <kerning first="109" second="106" amount="-1" />
+    <kerning first="109" second="221" amount="-2" />
+    <kerning first="110" second="84" amount="-2" />
+    <kerning first="110" second="89" amount="-2" />
+    <kerning first="110" second="106" amount="-1" />
+    <kerning first="110" second="221" amount="-2" />
+    <kerning first="111" second="84" amount="-2" />
+    <kerning first="111" second="89" amount="-2" />
+    <kerning first="111" second="106" amount="-2" />
+    <kerning first="111" second="221" amount="-2" />
+    <kerning first="112" second="84" amount="-3" />
+    <kerning first="112" second="89" amount="-2" />
+    <kerning first="112" second="106" amount="-1" />
+    <kerning first="112" second="221" amount="-2" />
+    <kerning first="113" second="84" amount="-2" />
+    <kerning first="113" second="86" amount="-1" />
+    <kerning first="113" second="89" amount="-2" />
+    <kerning first="113" second="221" amount="-2" />
+    <kerning first="114" second="74" amount="-2" />
+    <kerning first="114" second="84" amount="-2" />
+    <kerning first="114" second="90" amount="-2" />
+    <kerning first="114" second="106" amount="-1" />
+    <kerning first="114" second="198" amount="-2" />
+    <kerning first="115" second="84" amount="-2" />
+    <kerning first="115" second="89" amount="-2" />
+    <kerning first="115" second="106" amount="-2" />
+    <kerning first="115" second="221" amount="-2" />
+    <kerning first="116" second="106" amount="-1" />
+    <kerning first="117" second="84" amount="-2" />
+    <kerning first="117" second="106" amount="-1" />
+    <kerning first="118" second="65" amount="-1" />
+    <kerning first="118" second="84" amount="-2" />
+    <kerning first="118" second="90" amount="-2" />
+    <kerning first="118" second="106" amount="-2" />
+    <kerning first="118" second="192" amount="-1" />
+    <kerning first="118" second="193" amount="-1" />
+    <kerning first="118" second="194" amount="-1" />
+    <kerning first="118" second="195" amount="-1" />
+    <kerning first="118" second="196" amount="-1" />
+    <kerning first="118" second="197" amount="-1" />
+    <kerning first="118" second="198" amount="-2" />
+    <kerning first="119" second="84" amount="-3" />
+    <kerning first="119" second="89" amount="-1" />
+    <kerning first="119" second="106" amount="-2" />
+    <kerning first="119" second="221" amount="-1" />
+    <kerning first="120" second="84" amount="-2" />
+    <kerning first="120" second="106" amount="-1" />
+    <kerning first="121" second="65" amount="-1" />
+    <kerning first="121" second="84" amount="-3" />
+    <kerning first="121" second="88" amount="-1" />
+    <kerning first="121" second="89" amount="-1" />
+    <kerning first="121" second="90" amount="-1" />
+    <kerning first="121" second="106" amount="-1" />
+    <kerning first="121" second="192" amount="-1" />
+    <kerning first="121" second="193" amount="-1" />
+    <kerning first="121" second="194" amount="-1" />
+    <kerning first="121" second="195" amount="-1" />
+    <kerning first="121" second="196" amount="-1" />
+    <kerning first="121" second="197" amount="-1" />
+    <kerning first="121" second="198" amount="-1" />
+    <kerning first="255" second="84" amount="-1" />
+    <kerning first="122" second="84" amount="-3" />
+    <kerning first="255" second="65" amount="-1" />
+    <kerning first="122" second="106" amount="-1" />
+    <kerning first="122" second="221" amount="-1" />
+    <kerning first="192" second="84" amount="-2" />
+    <kerning first="192" second="86" amount="-2" />
+    <kerning first="192" second="87" amount="-1" />
+    <kerning first="192" second="89" amount="-2" />
+    <kerning first="192" second="106" amount="-2" />
+    <kerning first="192" second="118" amount="-1" />
+    <kerning first="192" second="221" amount="-2" />
+    <kerning first="192" second="253" amount="-1" />
+    <kerning first="254" second="221" amount="-2" />
+    <kerning first="193" second="84" amount="-2" />
+    <kerning first="193" second="86" amount="-2" />
+    <kerning first="193" second="87" amount="-1" />
+    <kerning first="193" second="89" amount="-2" />
+    <kerning first="193" second="106" amount="-2" />
+    <kerning first="193" second="221" amount="-2" />
+    <kerning first="254" second="106" amount="-2" />
+    <kerning first="254" second="89" amount="-2" />
+    <kerning first="194" second="84" amount="-2" />
+    <kerning first="194" second="86" amount="-2" />
+    <kerning first="194" second="87" amount="-1" />
+    <kerning first="194" second="89" amount="-2" />
+    <kerning first="194" second="106" amount="-1" />
+    <kerning first="194" second="221" amount="-2" />
+    <kerning first="254" second="84" amount="-2" />
+    <kerning first="253" second="198" amount="-1" />
+    <kerning first="195" second="84" amount="-2" />
+    <kerning first="195" second="86" amount="-2" />
+    <kerning first="195" second="87" amount="-1" />
+    <kerning first="195" second="89" amount="-2" />
+    <kerning first="195" second="106" amount="-1" />
+    <kerning first="195" second="221" amount="-2" />
+    <kerning first="253" second="197" amount="-1" />
+    <kerning first="253" second="196" amount="-1" />
+    <kerning first="196" second="84" amount="-2" />
+    <kerning first="196" second="86" amount="-2" />
+    <kerning first="196" second="87" amount="-2" />
+    <kerning first="196" second="89" amount="-2" />
+    <kerning first="196" second="106" amount="-1" />
+    <kerning first="196" second="118" amount="-1" />
+    <kerning first="196" second="221" amount="-2" />
+    <kerning first="253" second="195" amount="-1" />
+    <kerning first="253" second="194" amount="-1" />
+    <kerning first="197" second="84" amount="-2" />
+    <kerning first="197" second="86" amount="-2" />
+    <kerning first="197" second="87" amount="-2" />
+    <kerning first="197" second="89" amount="-2" />
+    <kerning first="197" second="106" amount="-2" />
+    <kerning first="197" second="118" amount="-1" />
+    <kerning first="197" second="221" amount="-2" />
+    <kerning first="197" second="253" amount="-1" />
+    <kerning first="197" second="255" amount="-1" />
+    <kerning first="198" second="106" amount="-2" />
+    <kerning first="199" second="67" amount="-1" />
+    <kerning first="199" second="71" amount="-1" />
+    <kerning first="199" second="79" amount="-1" />
+    <kerning first="199" second="81" amount="-1" />
+    <kerning first="199" second="102" amount="-1" />
+    <kerning first="199" second="106" amount="-2" />
+    <kerning first="199" second="116" amount="-1" />
+    <kerning first="199" second="118" amount="-2" />
+    <kerning first="199" second="119" amount="-1" />
+    <kerning first="199" second="121" amount="-2" />
+    <kerning first="199" second="199" amount="-1" />
+    <kerning first="253" second="193" amount="-1" />
+    <kerning first="199" second="205" amount="-1" />
+    <kerning first="199" second="206" amount="-1" />
+    <kerning first="253" second="192" amount="-1" />
+    <kerning first="253" second="106" amount="-2" />
+    <kerning first="199" second="210" amount="-1" />
+    <kerning first="199" second="211" amount="-1" />
+    <kerning first="199" second="212" amount="-1" />
+    <kerning first="199" second="213" amount="-1" />
+    <kerning first="199" second="214" amount="-1" />
+    <kerning first="253" second="65" amount="-1" />
+    <kerning first="199" second="253" amount="-2" />
+    <kerning first="199" second="255" amount="-1" />
+    <kerning first="200" second="106" amount="-2" />
+    <kerning first="252" second="221" amount="-1" />
+    <kerning first="252" second="106" amount="-2" />
+    <kerning first="200" second="253" amount="-1" />
+    <kerning first="201" second="106" amount="-2" />
+    <kerning first="252" second="89" amount="-1" />
+    <kerning first="252" second="84" amount="-2" />
+    <kerning first="202" second="106" amount="-1" />
+    <kerning first="251" second="106" amount="-2" />
+    <kerning first="251" second="84" amount="-1" />
+    <kerning first="203" second="106" amount="-1" />
+    <kerning first="203" second="121" amount="-1" />
+    <kerning first="250" second="106" amount="-2" />
+    <kerning first="204" second="106" amount="-2" />
+    <kerning first="205" second="106" amount="-2" />
+    <kerning first="206" second="106" amount="-2" />
+    <kerning first="207" second="106" amount="-2" />
+    <kerning first="208" second="106" amount="-1" />
+    <kerning first="209" second="106" amount="-2" />
+    <kerning first="210" second="84" amount="-1" />
+    <kerning first="210" second="106" amount="-1" />
+    <kerning first="211" second="84" amount="-1" />
+    <kerning first="211" second="106" amount="-1" />
+    <kerning first="212" second="84" amount="-1" />
+    <kerning first="212" second="106" amount="-2" />
+    <kerning first="213" second="84" amount="-1" />
+    <kerning first="213" second="106" amount="-1" />
+    <kerning first="214" second="84" amount="-1" />
+    <kerning first="214" second="89" amount="-1" />
+    <kerning first="214" second="106" amount="-2" />
+    <kerning first="214" second="221" amount="-1" />
+    <kerning first="216" second="106" amount="-1" />
+    <kerning first="217" second="106" amount="-1" />
+    <kerning first="218" second="106" amount="-1" />
+    <kerning first="219" second="106" amount="-1" />
+    <kerning first="220" second="106" amount="-2" />
+    <kerning first="221" second="65" amount="-2" />
+    <kerning first="221" second="74" amount="-2" />
+    <kerning first="221" second="97" amount="-1" />
+    <kerning first="221" second="99" amount="-1" />
+    <kerning first="221" second="100" amount="-2" />
+    <kerning first="221" second="101" amount="-2" />
+    <kerning first="221" second="103" amount="-2" />
+    <kerning first="221" second="106" amount="-2" />
+    <kerning first="221" second="111" amount="-1" />
+    <kerning first="221" second="112" amount="-2" />
+    <kerning first="221" second="113" amount="-1" />
+    <kerning first="221" second="115" amount="-1" />
+    <kerning first="221" second="192" amount="-2" />
+    <kerning first="221" second="193" amount="-2" />
+    <kerning first="221" second="194" amount="-2" />
+    <kerning first="221" second="195" amount="-2" />
+    <kerning first="221" second="196" amount="-2" />
+    <kerning first="221" second="197" amount="-2" />
+    <kerning first="221" second="198" amount="-2" />
+    <kerning first="221" second="224" amount="-1" />
+    <kerning first="221" second="225" amount="-2" />
+    <kerning first="221" second="226" amount="-1" />
+    <kerning first="221" second="228" amount="-1" />
+    <kerning first="221" second="229" amount="-1" />
+    <kerning first="221" second="230" amount="-2" />
+    <kerning first="221" second="231" amount="-2" />
+    <kerning first="221" second="232" amount="-1" />
+    <kerning first="221" second="233" amount="-2" />
+    <kerning first="221" second="234" amount="-1" />
+    <kerning first="221" second="235" amount="-1" />
+    <kerning first="221" second="240" amount="-1" />
+    <kerning first="221" second="242" amount="-1" />
+    <kerning first="221" second="243" amount="-1" />
+    <kerning first="221" second="244" amount="-1" />
+    <kerning first="221" second="246" amount="-1" />
+    <kerning first="221" second="248" amount="-1" />
+    <kerning first="222" second="84" amount="-2" />
+    <kerning first="222" second="88" amount="-1" />
+    <kerning first="222" second="89" amount="-2" />
+    <kerning first="222" second="90" amount="-2" />
+    <kerning first="222" second="106" amount="-3" />
+    <kerning first="222" second="198" amount="-1" />
+    <kerning first="222" second="221" amount="-2" />
+    <kerning first="223" second="84" amount="-1" />
+    <kerning first="223" second="89" amount="-1" />
+    <kerning first="223" second="106" amount="-2" />
+    <kerning first="223" second="221" amount="-1" />
+    <kerning first="224" second="84" amount="-1" />
+    <kerning first="224" second="89" amount="-2" />
+    <kerning first="224" second="106" amount="-1" />
+    <kerning first="224" second="221" amount="-2" />
+    <kerning first="225" second="84" amount="-1" />
+    <kerning first="225" second="89" amount="-1" />
+    <kerning first="225" second="106" amount="-1" />
+    <kerning first="225" second="221" amount="-1" />
+    <kerning first="226" second="84" amount="-2" />
+    <kerning first="226" second="86" amount="-1" />
+    <kerning first="226" second="89" amount="-2" />
+    <kerning first="226" second="106" amount="-2" />
+    <kerning first="226" second="221" amount="-1" />
+    <kerning first="227" second="106" amount="-1" />
+    <kerning first="228" second="84" amount="-3" />
+    <kerning first="228" second="86" amount="-1" />
+    <kerning first="228" second="89" amount="-1" />
+    <kerning first="228" second="106" amount="-2" />
+    <kerning first="228" second="221" amount="-1" />
+    <kerning first="229" second="84" amount="-1" />
+    <kerning first="229" second="86" amount="-1" />
+    <kerning first="229" second="89" amount="-1" />
+    <kerning first="229" second="106" amount="-2" />
+    <kerning first="229" second="221" amount="-1" />
+    <kerning first="230" second="84" amount="-2" />
+    <kerning first="230" second="89" amount="-2" />
+    <kerning first="230" second="106" amount="-2" />
+    <kerning first="230" second="221" amount="-2" />
+    <kerning first="231" second="84" amount="-2" />
+    <kerning first="231" second="89" amount="-2" />
+    <kerning first="231" second="221" amount="-1" />
+    <kerning first="232" second="84" amount="-2" />
+    <kerning first="250" second="84" amount="-1" />
+    <kerning first="232" second="89" amount="-1" />
+    <kerning first="232" second="106" amount="-2" />
+    <kerning first="232" second="221" amount="-2" />
+    <kerning first="233" second="84" amount="-1" />
+    <kerning first="233" second="89" amount="-1" />
+    <kerning first="233" second="106" amount="-2" />
+    <kerning first="233" second="221" amount="-1" />
+    <kerning first="234" second="84" amount="-2" />
+    <kerning first="234" second="86" amount="-1" />
+    <kerning first="234" second="89" amount="-1" />
+    <kerning first="234" second="106" amount="-2" />
+    <kerning first="234" second="221" amount="-1" />
+    <kerning first="235" second="84" amount="-2" />
+    <kerning first="235" second="89" amount="-1" />
+    <kerning first="235" second="106" amount="-2" />
+    <kerning first="235" second="221" amount="-1" />
+    <kerning first="236" second="106" amount="-2" />
+    <kerning first="237" second="106" amount="-2" />
+    <kerning first="238" second="106" amount="-1" />
+    <kerning first="249" second="221" amount="-1" />
+    <kerning first="239" second="106" amount="-2" />
+    <kerning first="240" second="106" amount="-2" />
+    <kerning first="241" second="106" amount="-2" />
+    <kerning first="242" second="84" amount="-1" />
+    <kerning first="242" second="89" amount="-1" />
+    <kerning first="242" second="106" amount="-2" />
+    <kerning first="242" second="221" amount="-1" />
+    <kerning first="243" second="84" amount="-1" />
+    <kerning first="243" second="89" amount="-1" />
+    <kerning first="243" second="106" amount="-2" />
+    <kerning first="243" second="221" amount="-1" />
+    <kerning first="244" second="84" amount="-1" />
+    <kerning first="244" second="89" amount="-1" />
+    <kerning first="244" second="106" amount="-2" />
+    <kerning first="244" second="221" amount="-1" />
+    <kerning first="245" second="84" amount="-1" />
+    <kerning first="245" second="106" amount="-2" />
+    <kerning first="246" second="84" amount="-2" />
+    <kerning first="246" second="89" amount="-1" />
+    <kerning first="246" second="106" amount="-2" />
+    <kerning first="246" second="221" amount="-1" />
+    <kerning first="248" second="84" amount="-1" />
+    <kerning first="248" second="106" amount="-2" />
+    <kerning first="249" second="84" amount="-2" />
+    <kerning first="249" second="89" amount="-1" />
+    <kerning first="249" second="106" amount="-2" />
+  </kernings>
+</font>

BIN
Samples/basic/bitmapfont/data/Comfortaa_Regular_22.tga


+ 49 - 0
Samples/basic/bitmapfont/data/LICENSE.txt

@@ -0,0 +1,49 @@
+The files "Comfortaa_Regular_22.fnt" and "Comfortaa_Regular_22.tga" represent a bitmap render of a subset of the font "Comfortaa Regular". The license of the font is attached below.
+
+
+-----------------------------------------------------------
+
+Copyright (c) 2010, Johan Aakerlund ([email protected]),
+with Reserved Font Name "Comfortaa".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
+
+5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.

+ 31 - 0
Samples/basic/bitmapfont/data/bitmapfont.rml

@@ -0,0 +1,31 @@
+<rml>
+<head>
+<title>Demo</title>
+<link type="text/template" href="../../../Assets/window.rml" />
+<style>
+body
+{
+	width: 600px;
+	height: 500px;
+	font-family: Comfortaa;
+	margin: auto;
+	font-size: 22px;
+}
+
+div#title_bar div#icon
+{
+	display: none;
+}
+
+div#content
+{
+	text-align: left;
+}
+</style>
+</head>
+<body template="window">
+	<p>This is a bitmap font sample!</p>
+	<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Urna neque viverra justo nec ultrices dui sapien eget mi. Risus quis varius quam quisque id. Amet est placerat in egestas erat imperdiet. Velit egestas dui id ornare arcu odio ut sem. Aliquet porttitor lacus luctus accumsan tortor posuere. Et malesuada fames ac turpis egestas integer eget. Enim nunc faucibus a pellentesque sit amet porttitor eget. Nunc pulvinar sapien et ligula. Sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus. Dolor sit amet consectetur adipiscing. Congue eu consequat ac felis donec et odio pellentesque. Nunc non blandit massa enim nec dui nunc mattis.</p>
+	<p>Posuere sollicitudin aliquam ultrices sagittis orci a scelerisque. Quam pellentesque nec nam aliquam sem et. Et tortor consequat id porta nibh venenatis. Facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat. Magna ac placerat vestibulum lectus mauris ultrices eros. Amet purus gravida quis blandit turpis cursus. Elit duis tristique sollicitudin nibh sit amet commodo nulla. Suscipit adipiscing bibendum est ultricies integer quis auctor elit sed. Iaculis at erat pellentesque adipiscing commodo elit at imperdiet. Pellentesque elit ullamcorper dignissim cras. Nunc eget lorem dolor sed viverra ipsum nunc. Ac felis donec et odio pellentesque diam volutpat commodo.</p>
+</body>
+</rml>

+ 314 - 0
Samples/basic/bitmapfont/src/FontEngineBitmap.cpp

@@ -0,0 +1,314 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <cstdio>
+#include <RmlUi/Core.h>
+#include <RmlUi/Core/StreamMemory.h>
+#include "FontEngineBitmap.h"
+
+namespace FontProviderBitmap
+{
+	static std::vector<std::unique_ptr<FontFaceBitmap>> fonts;
+
+
+	void Initialise()
+	{
+	}
+
+	void Shutdown()
+	{
+		fonts.clear();
+	}
+
+	bool LoadFontFace(const String& file_name, bool fallback_face)
+	{
+		// Load the xml meta file into memory
+		std::unique_ptr<byte[]> data;
+		size_t length = 0;
+
+		{
+			auto file_interface = Rml::Core::GetFileInterface();
+			auto handle = file_interface->Open(file_name);
+			if (!handle)
+				return false;
+
+			length = file_interface->Length(handle);
+			
+			data.reset(new byte[length]);
+
+			size_t read_length = file_interface->Read(data.get(), length, handle);
+
+			file_interface->Close(handle);
+
+			if (read_length != length || !data)
+				return false;
+		}
+
+		// Parse the xml font description
+		FontParserBitmap parser;
+
+		{
+			auto stream = std::make_unique<Rml::Core::StreamMemory>(data.get(), length);
+			stream->SetSourceURL(file_name);
+
+			parser.Parse(stream.get());
+
+			if (parser.family.empty() || parser.glyphs.empty() || parser.texture_name.empty() || parser.metrics.size == 0)
+				return false;
+
+			// Fill the remaining metrics
+			parser.metrics.underline_position = -parser.metrics.baseline - 1.f;
+			parser.metrics.underline_thickness = 1.f;
+		}
+
+		Texture texture;
+		texture.Set(parser.texture_name, file_name);
+
+		// Construct and add the font face
+		fonts.push_back(
+			std::make_unique<FontFaceBitmap>( 
+				parser.family, parser.style, parser.weight, parser.metrics, texture, parser.texture_dimensions, std::move(parser.glyphs), std::move(parser.kerning)
+		));
+
+		return true;
+	}
+
+	FontFaceBitmap* GetFontFaceHandle(const String& family, FontStyle style, FontWeight weight, int size)
+	{
+		FontFaceBitmap* best_match = nullptr;
+		int best_score = 0;
+
+		// Normally, we'd want to only match the font family exactly, but for this demo we create a very lenient heuristic.
+		for (const auto& font : fonts)
+		{
+			int score = 1;
+			if (font->GetFamily() == family)
+				score += 100;
+
+			score += 10 - std::min(10, std::abs(font->GetMetrics().size - size));
+
+			if (font->GetStyle() == style)
+				score += 2;
+			if (font->GetWeight() == weight)
+				score += 1;
+
+			if (score > best_score)
+			{
+				best_match = font.get();
+				best_score = score;
+			}
+		}
+		
+		return best_match;
+	}
+
+}
+
+
+FontFaceBitmap::FontFaceBitmap(String family, FontStyle style, FontWeight weight, FontMetrics metrics, Texture texture, Vector2f texture_dimensions, FontGlyphs&& glyphs, FontKerning&& kerning)
+	: family(family), style(style), weight(weight), metrics(metrics), texture(texture), texture_dimensions(texture_dimensions), glyphs(std::move(glyphs)), kerning(std::move(kerning)) 
+{}
+
+int FontFaceBitmap::GetStringWidth(const String& string, Character previous_character)
+{
+	int width = 0;
+
+	for (auto it_char = Rml::Core::StringIteratorU8(string); it_char; ++it_char)
+	{
+		Character character = *it_char;
+
+		auto it_glyph = glyphs.find(character);
+		if (it_glyph == glyphs.end())
+			continue;
+
+		const BitmapGlyph& glyph = it_glyph->second;
+
+		int kerning = GetKerning(previous_character, character);
+
+		width += glyph.advance + kerning;
+		previous_character = character;
+	}
+
+	return width;
+}
+
+int FontFaceBitmap::GenerateString(const String& string, const Vector2f& string_position, const Colourb& colour, GeometryList& geometry_list)
+{
+	int width = 0;
+
+	geometry_list.resize(1);
+	Rml::Core::Geometry& geometry = geometry_list[0];
+
+	geometry.SetTexture(&texture);
+
+	auto& vertices = geometry.GetVertices();
+	auto& indices = geometry.GetIndices();
+
+	vertices.reserve(string.size() * 4);
+	indices.reserve(string.size() * 6);
+
+	Vector2f position = string_position.Round();
+	Character previous_character = Character::Null;
+
+	for (auto it_char = Rml::Core::StringIteratorU8(string); it_char; ++it_char)
+	{
+		Character character = *it_char;
+
+		auto it_glyph = glyphs.find(character);
+		if (it_glyph == glyphs.end())
+			continue;
+
+		int kerning = GetKerning(previous_character, character);
+
+		width += kerning;
+		position.x += kerning;
+
+		const BitmapGlyph& glyph = it_glyph->second;
+
+		// Generate the geometry for the character.
+		vertices.resize(vertices.size() + 4);
+		indices.resize(indices.size() + 6);
+
+		Vector2f uv_top_left = glyph.position / texture_dimensions;
+		Vector2f uv_bottom_right = (glyph.position + glyph.dimension) / texture_dimensions;
+
+		Rml::Core::GeometryUtilities::GenerateQuad(
+			&vertices[0] + (vertices.size() - 4),
+			&indices[0] + (indices.size() - 6),
+			Vector2f(position + glyph.offset).Round(),
+			glyph.dimension,
+			colour,
+			uv_top_left,
+			uv_bottom_right,
+			(int)vertices.size() - 4
+		);
+
+		width += glyph.advance;
+		position.x += glyph.advance;
+
+		previous_character = character;
+	}
+
+	return width;
+}
+
+int FontFaceBitmap::GetKerning(Character left, Character right) const
+{
+	std::uint64_t key = (((std::uint64_t)left << 32) | (std::uint64_t)right);
+
+	auto it = kerning.find(key);
+	if (it != kerning.end())
+		return it->second;
+
+	return 0;
+}
+
+
+
+
+
+FontParserBitmap::~FontParserBitmap()
+{
+}
+
+// Called when the parser finds the beginning of an element tag.
+void FontParserBitmap::HandleElementStart(const String& name, const Rml::Core::XMLAttributes& attributes)
+{
+	if (name == "info")
+	{
+		family = Rml::Core::StringUtilities::ToLower( Get(attributes, "face", String()) );
+		metrics.size = Get(attributes, "size", 0);
+		metrics.line_height = Get(attributes, "height", 0);
+
+		style = Get(attributes, "italic", 0) == 1 ? FontStyle::Italic : FontStyle::Normal;
+		weight = Get(attributes, "bold", 0) == 1 ? FontWeight::Bold : FontWeight::Normal;
+	}
+	else if (name == "common")
+	{
+		metrics.line_height = Get(attributes, "lineHeight", 0);
+		metrics.baseline = Get(attributes, "base", 0);
+
+		texture_dimensions.x = Get(attributes, "scaleW", 0.f);
+		texture_dimensions.y = Get(attributes, "scaleH", 0.f);
+	}
+	else if (name == "page")
+	{
+		int id = Get(attributes, "id", -1);
+		if(id != 0)
+		{
+			Rml::Core::Log::Message(Rml::Core::Log::LT_WARNING, "Only single font textures are supported in Bitmap Font Engine");
+			return;
+		}
+		texture_name = Get(attributes, "file", String());
+	}
+	else if (name == "char")
+	{
+		Character character = (Character)Get(attributes, "id", 0);
+		if (character == Character::Null)
+			return;
+
+		BitmapGlyph& glyph = glyphs[character];
+
+		glyph.advance = Get(attributes, "xadvance", 0);
+
+		glyph.offset.x = Get(attributes, "xoffset", 0.f);
+		glyph.offset.y = Get(attributes, "yoffset", 0.f);
+		
+		glyph.position.x = Get(attributes, "x", 0.f);
+		glyph.position.y = Get(attributes, "y", 0.f);
+		glyph.dimension.x = Get(attributes, "width", 0.f);
+		glyph.dimension.y = Get(attributes, "height", 0.f);
+
+		if (character == (Character)'x')
+			metrics.x_height = (int)glyph.dimension.y;
+	}
+	else if (name == "kerning")
+	{
+		std::uint64_t first = (std::uint64_t)Get(attributes, "first", 0);
+		std::uint64_t second = (std::uint64_t)Get(attributes, "second", 0);
+		int amount = Get(attributes, "amount", 0);
+
+		if (first != 0 && second != 0 && amount != 0)
+		{
+			std::uint64_t key = ((first << 32) | second);
+			kerning[key] = amount;
+		}
+	}
+}
+
+// Called when the parser finds the end of an element tag.
+void FontParserBitmap::HandleElementEnd(const String& RMLUI_UNUSED_PARAMETER(name))
+{
+	RMLUI_UNUSED(name);
+}
+
+// Called when the parser encounters data.
+void FontParserBitmap::HandleData(const String& RMLUI_UNUSED_PARAMETER(data))
+{
+	RMLUI_UNUSED(data);
+}

+ 133 - 0
Samples/basic/bitmapfont/src/FontEngineBitmap.h

@@ -0,0 +1,133 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef FONTENGINEBITMAP_H
+#define FONTENGINEBITMAP_H
+
+#include <cstdint>
+#include <RmlUi/Core/Types.h>
+#include "FontEngineInterfaceBitmap.h"
+
+class FontFaceBitmap;
+
+namespace FontProviderBitmap
+{
+	void Initialise();
+	void Shutdown();
+	bool LoadFontFace(const String& file_name, bool fallback_face);
+	FontFaceBitmap* GetFontFaceHandle(const String& family, FontStyle style, FontWeight weight, int size);
+};
+
+
+struct BitmapGlyph {
+	int advance = 0;
+	Vector2f offset = { 0, 0 };
+	Vector2f position = { 0, 0 };
+	Vector2f dimension = { 0, 0 };
+};
+
+struct FontMetrics {
+	int size = 0;
+	int x_height = 0;
+	int line_height = 0;
+	int baseline = 0;
+	float underline_position = 0, underline_thickness = 0;
+};
+
+// A mapping of characters to their glyphs.
+using FontGlyphs = Rml::Core::UnorderedMap<Character, BitmapGlyph>;
+
+// Mapping of combined (left, right) character to kerning in pixels.
+using FontKerning = Rml::Core::UnorderedMap<std::uint64_t, int>;
+
+
+class FontFaceBitmap {
+public:
+	FontFaceBitmap(String family, FontStyle style, FontWeight weight, FontMetrics metrics, Texture texture, Vector2f texture_dimensions, FontGlyphs&& glyphs, FontKerning&& kerning);
+
+	// Get width of string.
+	int GetStringWidth(const String& string, Character prior_character);
+
+	// Generate the string geometry, returning its width.
+	int GenerateString(const String& string, const Vector2f& position, const Colourb& colour, GeometryList& geometry);
+
+
+	const FontMetrics& GetMetrics() const { return metrics; }
+	
+	const String& GetFamily() const { return family; }
+	FontStyle GetStyle() const { return style; }
+	FontWeight GetWeight() const { return weight; }
+
+private:
+	int GetKerning(Character left, Character right) const;
+
+	String family;
+	FontStyle style;
+	FontWeight weight;
+
+	FontMetrics metrics;
+
+	Texture texture;
+	Vector2f texture_dimensions;
+
+	FontGlyphs glyphs;
+	FontKerning kerning;
+};
+
+
+/*
+	Parses the font meta data from an xml file.
+*/
+
+class FontParserBitmap : public Rml::Core::BaseXMLParser
+{
+public:
+	FontParserBitmap() {}
+	virtual ~FontParserBitmap();
+
+	/// Called when the parser finds the beginning of an element tag.
+	void HandleElementStart(const String& name, const Rml::Core::XMLAttributes& attributes) override;
+	/// Called when the parser finds the end of an element tag.
+	void HandleElementEnd(const String& name) override;
+	/// Called when the parser encounters data.
+	void HandleData(const String& data) override;
+
+	String family;
+	FontStyle style = FontStyle::Normal;
+	FontWeight weight = FontWeight::Normal;
+
+	String texture_name;
+	Vector2f texture_dimensions = { 0, 0 };
+
+	FontMetrics metrics;
+	FontGlyphs glyphs;
+	FontKerning kerning;
+};
+
+
+#endif

+ 117 - 0
Samples/basic/bitmapfont/src/FontEngineInterfaceBitmap.cpp

@@ -0,0 +1,117 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <RmlUi/Core.h>
+#include "FontEngineInterfaceBitmap.h"
+#include "FontEngineBitmap.h"
+
+FontEngineInterfaceBitmap::FontEngineInterfaceBitmap()
+{
+	FontProviderBitmap::Initialise();
+}
+
+FontEngineInterfaceBitmap::~FontEngineInterfaceBitmap()
+{
+	FontProviderBitmap::Shutdown();
+}
+
+bool FontEngineInterfaceBitmap::LoadFontFace(const String& file_name, bool fallback_face)
+{
+	return FontProviderBitmap::LoadFontFace(file_name, fallback_face);
+}
+
+bool FontEngineInterfaceBitmap::LoadFontFace(const byte* data, int data_size, const String& font_family, FontStyle style, FontWeight weight, bool fallback_face)
+{
+	// We return 'true' here to allow the debugger to continue loading, but we will use our own fonts when it asks for a handle.
+	// The debugger might look a bit off with our own fonts, but hey it works.
+	if (font_family == "rmlui-debugger-font")
+		return true;
+
+	return false;
+}
+
+FontFaceHandle FontEngineInterfaceBitmap::GetFontFaceHandle(const String& family, FontStyle style, FontWeight weight, int size)
+{
+	auto handle = FontProviderBitmap::GetFontFaceHandle(family, style, weight, size);
+	return reinterpret_cast<FontFaceHandle>(handle);
+}
+
+FontEffectsHandle FontEngineInterfaceBitmap::PrepareFontEffects(FontFaceHandle handle, const FontEffectList& font_effects)
+{
+	// Font effects are not rendered in this implementation.
+	return 0;
+}
+
+int FontEngineInterfaceBitmap::GetSize(FontFaceHandle handle)
+{
+	auto handle_bitmap = reinterpret_cast<FontFaceBitmap*>(handle);
+	return handle_bitmap->GetMetrics().size;
+}
+
+int FontEngineInterfaceBitmap::GetXHeight(FontFaceHandle handle)
+{
+	auto handle_bitmap = reinterpret_cast<FontFaceBitmap*>(handle);
+	return handle_bitmap->GetMetrics().x_height;
+}
+
+int FontEngineInterfaceBitmap::GetLineHeight(FontFaceHandle handle)
+{
+	auto handle_bitmap = reinterpret_cast<FontFaceBitmap*>(handle);
+	return handle_bitmap->GetMetrics().line_height;
+}
+
+int FontEngineInterfaceBitmap::GetBaseline(FontFaceHandle handle)
+{
+	auto handle_bitmap = reinterpret_cast<FontFaceBitmap*>(handle);
+	return handle_bitmap->GetMetrics().baseline;
+}
+
+float FontEngineInterfaceBitmap::GetUnderline(FontFaceHandle handle, float& thickness)
+{
+	auto handle_bitmap = reinterpret_cast<FontFaceBitmap*>(handle);
+	thickness = handle_bitmap->GetMetrics().underline_thickness;
+	return handle_bitmap->GetMetrics().underline_position;
+}
+
+int FontEngineInterfaceBitmap::GetStringWidth(FontFaceHandle handle, const String& string, Character prior_character)
+{
+	auto handle_bitmap = reinterpret_cast<FontFaceBitmap*>(handle);
+	return handle_bitmap->GetStringWidth(string, prior_character);
+}
+
+int FontEngineInterfaceBitmap::GenerateString(FontFaceHandle handle, FontEffectsHandle font_effects_handle, const String& string,
+	const Vector2f& position, const Colourb& colour, GeometryList& geometry)
+{
+	auto handle_bitmap = reinterpret_cast<FontFaceBitmap*>(handle);
+	return handle_bitmap->GenerateString(string, position, colour, geometry);
+}
+
+int FontEngineInterfaceBitmap::GetVersion(FontFaceHandle handle)
+{
+	return 0;
+}

+ 99 - 0
Samples/basic/bitmapfont/src/FontEngineInterfaceBitmap.h

@@ -0,0 +1,99 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef FONTENGINEINTERFACEBITMAP_H
+#define FONTENGINEINTERFACEBITMAP_H
+
+#include <RmlUi/Core/Types.h>
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/FontEngineInterface.h>
+#include <RmlUi/Core/Spritesheet.h>
+
+using Rml::Core::FontFaceHandle;
+using Rml::Core::FontEffectsHandle;
+
+using Rml::Core::Vector2i;
+using Rml::Core::Vector2f;
+using Rml::Core::Colourb;
+using Rml::Core::Texture;
+using Rml::Core::String;
+using Rml::Core::Character;
+using Rml::Core::Style::FontStyle;
+using Rml::Core::Style::FontWeight;
+using Rml::Core::byte;
+
+using Rml::Core::FontEffectList;
+using Rml::Core::GeometryList;
+
+
+class RMLUICORE_API FontEngineInterfaceBitmap : public Rml::Core::FontEngineInterface
+{
+public:
+	FontEngineInterfaceBitmap();
+	virtual ~FontEngineInterfaceBitmap();
+
+	/// Called by RmlUi when it wants to load a font face from file.
+	bool LoadFontFace(const String& file_name, bool fallback_face) override;
+
+	/// Called by RmlUi when it wants to load a font face from memory, registered using the provided family, style, and weight.
+	/// @param[in] data A pointer to the data.
+	bool LoadFontFace(const byte* data, int data_size, const String& family, FontStyle style, FontWeight weight, bool fallback_face) override;
+
+	/// Called by RmlUi when a font configuration is resolved for an element. Should return a handle that 
+	/// can later be used to resolve properties of the face, and generate string geometry to be rendered.
+	FontFaceHandle GetFontFaceHandle(const String& family, FontStyle style, FontWeight weight, int size) override;
+
+	/// Called by RmlUi when a list of font effects is resolved for an element with a given font face.
+	FontEffectsHandle PrepareFontEffects(FontFaceHandle handle, const FontEffectList& font_effects) override;
+
+	/// Should return the point size of this font face.
+	int GetSize(FontFaceHandle handle) override;
+	/// Should return the pixel height of a lower-case x in this font face.
+	int GetXHeight(FontFaceHandle handle) override;
+	/// Should return the default height between this font face's baselines.
+	int GetLineHeight(FontFaceHandle handle) override;
+
+	/// Should return the font's baseline, as a pixel offset from the bottom of the font.
+	int GetBaseline(FontFaceHandle handle) override;
+
+	/// Should return the font's underline, as a pixel offset from the bottom of the font.
+	float GetUnderline(FontFaceHandle handle, float& thickness) override;
+
+	/// Called by RmlUi when it wants to retrieve the width of a string when rendered with this handle.
+	int GetStringWidth(FontFaceHandle handle, const String& string, Character prior_character = Character::Null) override;
+
+	/// Called by RmlUi when it wants to retrieve the geometry required to render a single line of text.
+	int GenerateString(FontFaceHandle face_handle, FontEffectsHandle font_effects_handle, const String& string, const Vector2f& position, const Colourb& colour, GeometryList& geometry) override;
+
+	/// Called by RmlUi to determine if the text geometry is required to be re-generated.eometry.
+	int GetVersion(FontFaceHandle handle) override;
+};
+
+
+
+#endif

+ 29 - 4
Samples/basic/bitmapfont/src/main.cpp

@@ -32,6 +32,17 @@
 #include <Shell.h>
 #include <ShellRenderInterfaceOpenGL.h>
 
+#include "FontEngineInterfaceBitmap.h"
+
+/*
+
+	This demo shows how to create a custom bitmap font engine implementation. 
+	
+	It should work even when RmlUi is compiled without the default font engine (see CMake flag 'NO_FONT_INTERFACE_DEFAULT').
+	See the interface in 'FontEngineInterfaceBitmap.h' and the implementation in 'FontEngineBitmap.h'.
+
+*/
+
 Rml::Core::Context* context = nullptr;
 
 ShellRenderInterfaceExtensions *shell_renderer;
@@ -87,6 +98,10 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	ShellSystemInterface system_interface;
 	Rml::Core::SetSystemInterface(&system_interface);
 
+	// Construct and load the font interface.
+	FontEngineInterfaceBitmap font_interface;
+	Rml::Core::SetFontEngineInterface(&font_interface);
+
 	Rml::Core::Initialise();
 
 	// Create the main RmlUi context and set it on the shell's input layer.
@@ -103,11 +118,21 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	shell_renderer->SetContext(context);
 
     // Load bitmap font
-    Rml::Core::GetFontEngineInterface()->LoadFontFace("assets/Arial.fnt");
-	
-    // Load and show the demo document.
-	if(Rml::Core::ElementDocument* document = context->LoadDocument("assets/bitmapfont.rml"))
+	if (!Rml::Core::LoadFontFace("basic/bitmapfont/data/Comfortaa_Regular_22.fnt"))
+	{
+		Rml::Core::Shutdown();
+		Shell::Shutdown();
+		return -1;
+	}
+
+	// Load and show the demo document.
+	if (Rml::Core::ElementDocument * document = context->LoadDocument("basic/bitmapfont/data/bitmapfont.rml"))
+	{
+		if (auto el = document->GetElementById("title"))
+			el->SetInnerRML("Bitmap font");
+
 		document->Show();
+	}
 
 	Shell::EventLoop(GameLoop);
 

+ 19 - 14
Samples/basic/demo/data/demo.rml

@@ -116,20 +116,19 @@ button:focus {
 {
 	decorator: ninepatch(button-active, button-inner-active);
 }
-
-@decorator left-arrow : tiled-box {
-	top-image-src: ../../../assets/present.tga;
-	center-image-src: ../../../assets/present.tga;
-	left-image-src: ../../../assets/present.tga;
+p.emojis
+{
+	text-align: left;
+	font-size: 35px;
+	color: #b33;
 }
 
-.left-arrow {
-	width: 32dp;
-	height: 32dp;
-	decorator: left-arrow;
+textarea {
+	font-size: 18px;
+	font-effect: outline(2px #006600);
+	color: #ddd;
+	
 }
-
-
 </style>
 </head>
 
@@ -138,6 +137,13 @@ button:focus {
 <div style="font-size: 0.85em; text-align: left;" id="fps"></div>
 
 <tabset id="menu">
+<tab>Welcome</tab>
+<panel id="welcome">
+	<p class="emojis">RmlUi 😍</p>
+	<p>Have fun fiddling about in this (incomplete) demo.</p>
+	<p>Press 'F8' to open up the debugger.</p>
+	<p class="emojis" style="margin-top: 1em;">🎉</p>
+</panel>
 <tab>Decorators</tab>
 <panel id="decorators">
 	<p>Image vs ninepatch decorator:</p>
@@ -168,10 +174,9 @@ button:focus {
 </panel>
 <tab>Controls</tab>
 <panel>
-	<div>Type something here: <input style="vertical-align: -7px;" size="10" type="text" value="Sample text"/></div>
-	<textarea cols="30" rows="5" wrap="nowrap">Hello World!</textarea>
+	<div>Type something here: <input style="vertical-align: -7px;" size="10" type="text" maxlength="12" value="Sample text"/></div>
+	<textarea cols="30" rows="5" wrap="nowrap">😍 Hello 🌐 World! 😎</textarea>
 </panel>
 </tabset>
-<div class="left-arrow"/>
 </body>
 </rml>

+ 4 - 4
Samples/basic/sdl2/src/main.cpp

@@ -89,10 +89,10 @@ int main(int argc, char **argv)
 	if(!Rml::Core::Initialise())
 		return 1;
 
-	Rml::Core::GetFontEngineInterface()->LoadFontFace("assets/Delicious-Bold.otf");
-	Rml::Core::GetFontEngineInterface()->LoadFontFace("assets/Delicious-BoldItalic.otf");
-	Rml::Core::GetFontEngineInterface()->LoadFontFace("assets/Delicious-Italic.otf");
-	Rml::Core::GetFontEngineInterface()->LoadFontFace("assets/Delicious-Roman.otf");
+	Rml::Core::LoadFontFace("assets/Delicious-Bold.otf");
+	Rml::Core::LoadFontFace("assets/Delicious-BoldItalic.otf");
+	Rml::Core::LoadFontFace("assets/Delicious-Italic.otf");
+	Rml::Core::LoadFontFace("assets/Delicious-Roman.otf");
 
 	Rml::Core::Context *Context = Rml::Core::CreateContext("default",
 		Rml::Core::Vector2i(window_width, window_height));

+ 4 - 4
Samples/basic/sfml2/src/main.cpp

@@ -89,10 +89,10 @@ int main(int argc, char **argv)
 	if(!Rml::Core::Initialise())
 		return 1;
 
-	Rml::Core::GetFontEngineInterface()->LoadFontFace("assets/Delicious-Bold.otf");
-	Rml::Core::GetFontEngineInterface()->LoadFontFace("assets/Delicious-BoldItalic.otf");
-	Rml::Core::GetFontEngineInterface()->LoadFontFace("assets/Delicious-Italic.otf");
-	Rml::Core::GetFontEngineInterface()->LoadFontFace("assets/Delicious-Roman.otf");
+	Rml::Core::LoadFontFace("assets/Delicious-Bold.otf");
+	Rml::Core::LoadFontFace("assets/Delicious-BoldItalic.otf");
+	Rml::Core::LoadFontFace("assets/Delicious-Italic.otf");
+	Rml::Core::LoadFontFace("assets/Delicious-Roman.otf");
 
 	Rml::Core::Context *Context = Rml::Core::CreateContext("default",
 		Rml::Core::Vector2i(MyWindow.getSize().x, MyWindow.getSize().y));

+ 1 - 1
Samples/shell/include/Input.h

@@ -53,7 +53,7 @@ public:
 	/// @param[in] key_identifier The key to generate a character code for.
 	/// @param[in] key_modifier_state The configuration of the key modifiers.
 	/// @return The character code.
-	static Rml::Core::word GetCharacterCode(Rml::Core::Input::KeyIdentifier key_identifier, int key_modifier_state);
+	static Rml::Core::Character GetCharacterCode(Rml::Core::Input::KeyIdentifier key_identifier, int key_modifier_state);
 
 protected:
 	static Rml::Core::Context* context;

+ 2 - 2
Samples/shell/include/Shell.h

@@ -80,10 +80,10 @@ public:
 	static void SetMouseCursor(const Rml::Core::String& cursor_name);
 
 	/// Set clipboard text.
-	static void SetClipboardText(const Rml::Core::WString& text);
+	static void SetClipboardText(const Rml::Core::String& text);
 
 	/// Get clipboard text.
-	static void GetClipboardText(Rml::Core::WString& text);
+	static void GetClipboardText(Rml::Core::String& text);
 	
 	/// Sets the context to send window resized events to.
 	/// @param[in] context The context to send  events to.

+ 2 - 2
Samples/shell/include/ShellSystemInterface.h

@@ -49,11 +49,11 @@ public:
 
 	/// Set clipboard text.
 	/// @param[in] text Text to apply to clipboard.
-	void SetClipboardText(const Rml::Core::WString& text) override;
+	void SetClipboardText(const Rml::Core::String& text) override;
 
 	/// Get clipboard text.
 	/// @param[out] text Retrieved text from clipboard.
-	void GetClipboardText(Rml::Core::WString& text) override;
+	void GetClipboardText(Rml::Core::String& text) override;
 };
 
 #endif

+ 4 - 3
Samples/shell/include/win32/InputWin32.h

@@ -30,10 +30,12 @@
 #define RMLUIINPUTWIN32_H
 
 #include <Input.h>
-#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0500
+#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0501
 #undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0500
+#define _WIN32_WINNT 0x0501
 #endif
+#define UNICODE
+#define _UNICODE
 #include <windows.h>
 
 /**
@@ -50,7 +52,6 @@ public:
 
 	/// Process the Windows message.
 	static void ProcessWindowsEvent(UINT message, WPARAM w_param, LPARAM l_param);
-private:
 };
 
 #endif

+ 11 - 9
Samples/shell/src/Input.cpp

@@ -316,8 +316,10 @@ void Input::SetContext(Rml::Core::Context* _context)
 
 
 // Returns the character code for a key identifer / key modifier combination.
-Rml::Core::word Input::GetCharacterCode(Rml::Core::Input::KeyIdentifier key_identifier, int key_modifier_state)
+Rml::Core::Character Input::GetCharacterCode(Rml::Core::Input::KeyIdentifier key_identifier, int key_modifier_state)
 {
+	using Rml::Core::Character;
+
 	// Check if we have a keycode capable of generating characters on the main keyboard (ie, not on the numeric
 	// keypad; that is dealt with below).
 	if (key_identifier <= Rml::Core::Input::KI_OEM_102)
@@ -328,28 +330,28 @@ Rml::Core::word Input::GetCharacterCode(Rml::Core::Input::KeyIdentifier key_iden
 
 		// Return character code based on identifier and modifiers
 		if (shift && !capslock)
-			return ascii_map[1][key_identifier];
+			return (Character)ascii_map[1][key_identifier];
 
 		if (shift && capslock)
-			return ascii_map[2][key_identifier];	
+			return (Character)ascii_map[2][key_identifier];
 
 		if (!shift && capslock)
-			return ascii_map[3][key_identifier];
+			return (Character)ascii_map[3][key_identifier];
 
-		return ascii_map[0][key_identifier];
+		return (Character)ascii_map[0][key_identifier];
 	}
 
 	// Check if we have a keycode from the numeric keypad.
 	else if (key_identifier <= Rml::Core::Input::KI_OEM_NEC_EQUAL)
 	{
 		if (key_modifier_state & Rml::Core::Input::KM_NUMLOCK)
-			return keypad_map[0][key_identifier - Rml::Core::Input::KI_NUMPAD0];
+			return (Character)keypad_map[0][key_identifier - Rml::Core::Input::KI_NUMPAD0];
 		else
-			return keypad_map[1][key_identifier - Rml::Core::Input::KI_NUMPAD0];
+			return (Character)keypad_map[1][key_identifier - Rml::Core::Input::KI_NUMPAD0];
 	}
 
 	else if (key_identifier == Rml::Core::Input::KI_RETURN)
-		return '\n';
+		return (Character)'\n';
 
-	return 0;
+	return Character::Null;
 }

+ 5 - 2
Samples/shell/src/Shell.cpp

@@ -32,15 +32,18 @@
 /// Loads the default fonts from the given path.
 void Shell::LoadFonts(const char* directory)
 {
-	Rml::Core::String font_names[4];
+	Rml::Core::String font_names[5];
 	font_names[0] = "Delicious-Roman.otf";
 	font_names[1] = "Delicious-Italic.otf";
 	font_names[2] = "Delicious-Bold.otf";
 	font_names[3] = "Delicious-BoldItalic.otf";
+	font_names[4] = "NotoEmoji-Regular.ttf";
+
+	const int fallback_face = 4;
 
 	for (int i = 0; i < sizeof(font_names) / sizeof(Rml::Core::String); i++)
 	{
-		Rml::Core::GetFontEngineInterface()->LoadFontFace(Rml::Core::String(directory) + font_names[i]);
+		Rml::Core::LoadFontFace(Rml::Core::String(directory) + font_names[i], i == fallback_face);
 	}
 }
 

+ 2 - 2
Samples/shell/src/ShellSystemInterface.cpp

@@ -40,12 +40,12 @@ void ShellSystemInterface::SetMouseCursor(const Rml::Core::String& cursor_name)
 	Shell::SetMouseCursor(cursor_name);
 }
 
-void ShellSystemInterface::SetClipboardText(const Rml::Core::WString& text)
+void ShellSystemInterface::SetClipboardText(const Rml::Core::String& text)
 {
 	Shell::SetClipboardText(text);
 }
 
-void ShellSystemInterface::GetClipboardText(Rml::Core::WString& text)
+void ShellSystemInterface::GetClipboardText(Rml::Core::String& text)
 {
 	Shell::GetClipboardText(text);
 }

+ 2 - 2
Samples/shell/src/macosx/InputMacOSX.cpp

@@ -129,8 +129,8 @@ OSStatus InputMacOSX::EventHandler(EventHandlerCallRef next_handler, EventRef ev
 						if (key_identifier != Rml::Core::Input::KI_UNKNOWN)
 							context->ProcessKeyDown(key_identifier, key_modifier_state);
 
-						Rml::Core::word character = GetCharacterCode(key_identifier, key_modifier_state);
-						if (character > 0)
+						Rml::Core::Character character = GetCharacterCode(key_identifier, key_modifier_state);
+						if (character != Rml::Core::Character::Null)
 							context->ProcessTextInput(character);
 					}
 				}

+ 3 - 3
Samples/shell/src/macosx/ShellMacOSX.cpp

@@ -55,7 +55,7 @@ static const EventTypeSpec WINDOW_EVENTS[] = {
 
 static WindowRef window;
 static timeval start_time;
-static Rml::Core::WString clipboard_text;
+static Rml::Core::String clipboard_text;
 
 static std::unique_ptr<ShellFileInterface> file_interface;
 
@@ -258,13 +258,13 @@ void Shell::SetMouseCursor(const Rml::Core::String& cursor_name)
 }
 
 
-void Shell::SetClipboardText(const Rml::Core::WString& text)
+void Shell::SetClipboardText(const Rml::Core::String& text)
 {
 	// Todo: interface with system clipboard
 	clipboard_text = text;
 }
 
-void Shell::GetClipboardText(Rml::Core::WString& text)
+void Shell::GetClipboardText(Rml::Core::String& text)
 {
 	// Todo: interface with system clipboard
 	text = clipboard_text;

+ 34 - 7
Samples/shell/src/win32/InputWin32.cpp

@@ -29,6 +29,7 @@
 #include <win32/InputWin32.h>
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/StringUtilities.h>
 #include <RmlUi/Debugger.h>
 #include <Shell.h>
 
@@ -52,7 +53,7 @@ void InputWin32::ProcessWindowsEvent(UINT message, WPARAM w_param, LPARAM l_para
 {
 	if (context == nullptr)
 		return;
-
+	
 	// Process all mouse and keyboard events
 	switch (message)
 	{
@@ -104,14 +105,40 @@ void InputWin32::ProcessWindowsEvent(UINT message, WPARAM w_param, LPARAM l_para
 		}
 		break;
 
+
 		case WM_CHAR:
 		{
-			// Only send through printable characters.
-			if (w_param >= 32)
-				context->ProcessTextInput((Rml::Core::word) w_param);
-			// Or endlines - Windows sends them through as carriage returns.
-			else if (w_param == '\r')
-				context->ProcessTextInput((Rml::Core::word) '\n');
+			static char16_t first_u16_code_unit = 0;
+
+			char16_t c = (char16_t)w_param;
+			Rml::Core::Character character = (Rml::Core::Character)c;
+
+			// Windows sends two-wide characters as two messages.
+			if (c >= 0xD800 && c < 0xDC00)
+			{
+				// First 16-bit code unit of a two-wide character.
+				first_u16_code_unit = c;
+			}
+			else
+			{
+				if (c >= 0xDC00 && c < 0xE000 && first_u16_code_unit != 0)
+				{
+					// Second 16-bit code unit of a two-wide character.
+					Rml::Core::String utf8 = Rml::Core::StringUtilities::ToUTF8({ first_u16_code_unit, c });
+					character = Rml::Core::StringUtilities::ToCharacter(utf8.data());
+				}
+				else if (c == '\r')
+				{
+					// Windows sends new-lines as carriage returns, convert to endlines.
+					character = (Rml::Core::Character)'\n';
+				}
+
+				first_u16_code_unit = 0;
+
+				// Only send through printable characters.
+				if ((char32_t)character >= 32 || character == (Rml::Core::Character)'\n')
+					context->ProcessTextInput(character);
+			}
 		}
 		break;
 

+ 26 - 23
Samples/shell/src/win32/ShellWin32.cpp

@@ -30,7 +30,6 @@
 #include <RmlUi/Core.h>
 #include <win32/InputWin32.h>
 #include "ShellFileInterface.h"
-#include <windows.h>
 #include <stdio.h>
 #include <stdarg.h>
 
@@ -38,7 +37,7 @@ static LRESULT CALLBACK WindowProcedure(HWND window_handle, UINT message, WPARAM
 
 static bool activated = true;
 static bool running = false;
-static const char* instance_name = nullptr;
+static Rml::Core::U16String instance_name;
 static HWND window_handle = nullptr;
 static HINSTANCE instance_handle = nullptr;
 
@@ -65,10 +64,10 @@ bool Shell::Initialise()
 	time_frequency = 1.0 / (double) time_ticks_per_second.QuadPart;
 
 	// Load cursors
-	cursor_default = LoadCursorA(nullptr, IDC_ARROW);
-	cursor_move = LoadCursorA(nullptr, IDC_SIZEALL);
-	cursor_cross = LoadCursorA(nullptr, IDC_CROSS);
-	cursor_unavailable = LoadCursorA(nullptr, IDC_NO);
+	cursor_default = LoadCursor(nullptr, IDC_ARROW);
+	cursor_move = LoadCursor(nullptr, IDC_SIZEALL);
+	cursor_cross = LoadCursor(nullptr, IDC_CROSS);
+	cursor_unavailable = LoadCursor(nullptr, IDC_NO);
 
 	Rml::Core::String root = FindSamplesRoot();
 	
@@ -104,9 +103,11 @@ Rml::Core::String Shell::FindSamplesRoot()
 }
 
 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* in_name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize)
 {
-	WNDCLASS window_class;
+	WNDCLASSW window_class;
+
+	Rml::Core::U16String name = Rml::Core::StringUtilities::ToUTF16(Rml::Core::String(in_name));
 
 	// Fill out the window class struct.
 	window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
@@ -118,9 +119,9 @@ bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_
 	window_class.hCursor = cursor_default;
 	window_class.hbrBackground = nullptr;
 	window_class.lpszMenuName = nullptr;
-	window_class.lpszClassName = name;
+	window_class.lpszClassName = (LPCWSTR)name.data();
 
-	if (!RegisterClass(&window_class))
+	if (!RegisterClassW(&window_class))
 	{
 		DisplayError("Could not register window class.");
 
@@ -128,9 +129,9 @@ bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_
 		return false;
 	}
 
-	window_handle = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
-								   name,	// Window class name.
-								   name,
+	window_handle = CreateWindowExW(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
+								   (LPCWSTR)name.data(),	// Window class name.
+								   (LPCWSTR)name.data(),
 								   WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
 								   0, 0,	// Window position.
 								   width, height,// Window size.
@@ -190,7 +191,7 @@ void Shell::CloseWindow()
 	}
 
 	DestroyWindow(window_handle);  
-	UnregisterClass(instance_name, instance_handle);
+	UnregisterClassW((LPCWSTR)instance_name.data(), instance_handle);
 }
 
 // Returns a platform-dependent handle to the window.
@@ -241,7 +242,7 @@ void Shell::DisplayError(const char* fmt, ...)
 	buffer[len + 1] = '\0';
 	va_end(argument_list);
 
-	MessageBox(window_handle, buffer, "Shell Error", MB_OK);
+	MessageBox(window_handle, (LPCWSTR)Rml::Core::StringUtilities::ToUTF16(buffer).c_str(), L"Shell Error", MB_OK);
 }
 
 void Shell::Log(const char* fmt, ...)
@@ -261,7 +262,7 @@ void Shell::Log(const char* fmt, ...)
 	buffer[len + 1] = '\0';
 	va_end(argument_list);
 
-	OutputDebugString(buffer);
+	OutputDebugString((LPCWSTR)Rml::Core::StringUtilities::ToUTF16(buffer).c_str());
 }
 
 double Shell::GetElapsedTime() 
@@ -294,7 +295,7 @@ void Shell::SetMouseCursor(const Rml::Core::String& cursor_name)
 	}
 }
 
-void Shell::SetClipboardText(const Rml::Core::WString& text)
+void Shell::SetClipboardText(const Rml::Core::String& text_utf8)
 {
 	if (window_handle)
 	{
@@ -303,7 +304,9 @@ void Shell::SetClipboardText(const Rml::Core::WString& text)
 
 		EmptyClipboard();
 
-		size_t size = sizeof(wchar_t) * (text.size() + 1);
+		const Rml::Core::U16String text = Rml::Core::StringUtilities::ToUTF16(text_utf8);
+
+		size_t size = sizeof(char16_t) * (text.size() + 1);
 
 		HGLOBAL clipboard_data = GlobalAlloc(GMEM_FIXED, size);
 		memcpy(clipboard_data, text.data(), size);
@@ -318,7 +321,7 @@ void Shell::SetClipboardText(const Rml::Core::WString& text)
 	}
 }
 
-void Shell::GetClipboardText(Rml::Core::WString& text)
+void Shell::GetClipboardText(Rml::Core::String& text)
 {
 	if (window_handle)
 	{
@@ -332,9 +335,9 @@ void Shell::GetClipboardText(Rml::Core::WString& text)
 			return;
 		}
 
-		const wchar_t* clipboard_text = (const wchar_t*)GlobalLock(clipboard_data);
+		const char16_t* clipboard_text = (const char16_t*)GlobalLock(clipboard_data);
 		if (clipboard_text)
-			text = clipboard_text;
+			text = Rml::Core::StringUtilities::ToUTF8(clipboard_text);
 		GlobalUnlock(clipboard_data);
 
 		CloseClipboard();
@@ -369,8 +372,8 @@ static LRESULT CALLBACK WindowProcedure(HWND window_handle, UINT message, WPARAM
 
 		case WM_SIZE:
 		{
-			int width = LOWORD(l_param);;
-			int height = HIWORD(l_param);;
+			int width = LOWORD(l_param);
+			int height = HIWORD(l_param);
 			shell_renderer->SetViewport(width, height);
 		}
 		break;

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

@@ -168,8 +168,8 @@ void InputX11::ProcessXEvent(Display* display, const XEvent& event)
 			if (key_identifier != Rml::Core::Input::KI_UNKNOWN)
 				context->ProcessKeyDown(key_identifier, key_modifier_state);
 
-			Rml::Core::word character = GetCharacterCode(key_identifier, key_modifier_state);
-			if (character > 0)
+			Rml::Core::Character character = GetCharacterCode(key_identifier, key_modifier_state);
+			if (character != Rml::Core::Character::Null)
 				context->ProcessTextInput(character);
 		}
 		break;

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

@@ -46,7 +46,7 @@
 static bool running = false;
 static int screen = -1;
 static timeval start_time;
-static Rml::Core::WString clipboard_text;
+static Rml::Core::String clipboard_text;
 
 static std::unique_ptr<ShellFileInterface> file_interface;
 
@@ -346,13 +346,13 @@ void Shell::SetMouseCursor(const Rml::Core::String& cursor_name)
 	// Not implemented
 }
 
-void Shell::SetClipboardText(const Rml::Core::WString& text)
+void Shell::SetClipboardText(const Rml::Core::String& text)
 {
 	// Todo: interface with system clipboard
 	clipboard_text = text;
 }
 
-void Shell::GetClipboardText(Rml::Core::WString& text)
+void Shell::GetClipboardText(Rml::Core::String& text)
 {
 	// Todo: interface with system clipboard
 	text = clipboard_text;

+ 1 - 1
Source/Controls/ElementFormControlTextArea.cpp

@@ -122,7 +122,7 @@ bool ElementFormControlTextArea::GetWordWrap()
 // Returns the control's inherent size, based on the length of the input field and the current font size.
 bool ElementFormControlTextArea::GetIntrinsicDimensions(Rml::Core::Vector2f& dimensions)
 {
-	dimensions.x = (float) (GetNumColumns() * Core::ElementUtilities::GetStringWidth(this, L"m"));
+	dimensions.x = (float) (GetNumColumns() * Core::ElementUtilities::GetStringWidth(this, "m"));
 	dimensions.y = (float)GetNumRows() * GetLineHeight();
 
 	return true;

+ 1 - 1
Source/Controls/InputTypeText.cpp

@@ -114,7 +114,7 @@ void InputTypeText::ProcessDefaultAction(Core::Event& RMLUI_UNUSED_PARAMETER(eve
 // Sizes the dimensions to the element's inherent size.
 bool InputTypeText::GetIntrinsicDimensions(Rml::Core::Vector2f& dimensions)
 {
-	dimensions.x = (float) (size * Core::ElementUtilities::GetStringWidth(element, L"m"));
+	dimensions.x = (float) (size * Core::ElementUtilities::GetStringWidth(element, "m"));
 	dimensions.y = element->GetLineHeight() + 2.0f;
 
 	return true;

+ 175 - 78
Source/Controls/WidgetTextInput.cpp

@@ -31,6 +31,7 @@
 #include "../../Include/RmlUi/Core.h"
 #include "../../Include/RmlUi/Controls/ElementFormControl.h"
 #include "../../Include/RmlUi/Core/SystemInterface.h"
+#include "../../Include/RmlUi/Core/StringUtilities.h"
 #include "../Core/Clock.h"
 
 namespace Rml {
@@ -114,7 +115,7 @@ WidgetTextInput::~WidgetTextInput()
 // Sets the value of the text field.
 void WidgetTextInput::SetValue(const Core::String& value)
 {
-	text_element->SetText(Core::StringUtilities::ToUCS2(value));
+	text_element->SetText(value);
 	FormatElement();
 
 	UpdateRelativeCursor();
@@ -128,13 +129,25 @@ void WidgetTextInput::SetMaxLength(int _max_length)
 		max_length = _max_length;
 		if (max_length >= 0)
 		{
-			Core::WString value = Core::StringUtilities::ToUCS2( GetElement()->GetAttribute< Rml::Core::String >("value", "") );
-			if ((int) value.size() > max_length)
+			Core::String value = GetElement()->GetAttribute< Rml::Core::String >("value", "");
+
+			int num_characters = 0;
+			size_t i_erase = value.size();
+
+			for (auto it = Core::StringIteratorU8(value); it; ++it)
 			{
-				Rml::Core::String new_value;
-				new_value = Core::StringUtilities::ToUTF8(Core::WString(value.c_str(), value.c_str() + max_length));
+				num_characters += 1;
+				if (num_characters > max_length)
+				{
+					i_erase = size_t(it.Offset());
+					break;
+				}
+			}
 
-				GetElement()->SetAttribute("value", new_value);
+			if(i_erase < value.size())
+			{
+				value.erase(i_erase);
+				GetElement()->SetAttribute("value", value);
 			}
 		}
 	}
@@ -146,6 +159,13 @@ int WidgetTextInput::GetMaxLength() const
 	return max_length;
 }
 
+int WidgetTextInput::GetLength() const
+{
+	Core::String value = GetElement()->GetAttribute< Core::String >("value", "");
+	size_t result = Core::StringUtilities::LengthUTF8(value);
+	return (int)result;
+}
+
 // Update the colours of the selected text.
 void WidgetTextInput::UpdateSelectionColours()
 {
@@ -247,7 +267,7 @@ const Rml::Core::Vector2f& WidgetTextInput::GetTextDimensions() const
 }
 
 // Gets the parent element containing the widget.
-Core::Element* WidgetTextInput::GetElement()
+Core::Element* WidgetTextInput::GetElement() const
 {
 	return parent;
 }
@@ -282,10 +302,10 @@ void WidgetTextInput::ProcessEvent(Core::Event& event)
 		switch (key_identifier)
 		{
 		case Core::Input::KI_NUMPAD4:	if (numlock) break;
-		case Core::Input::KI_LEFT:		MoveCursorHorizontal(-1, shift); break;
+		case Core::Input::KI_LEFT:		MoveCursorHorizontal(ctrl ? CursorMovement::PreviousWord : CursorMovement::Left, shift); break;
 
 		case Core::Input::KI_NUMPAD6:	if (numlock) break;
-		case Core::Input::KI_RIGHT:		MoveCursorHorizontal(1, shift); break;
+		case Core::Input::KI_RIGHT:		MoveCursorHorizontal(ctrl ? CursorMovement::NextWord : CursorMovement::Right, shift); break;
 
 		case Core::Input::KI_NUMPAD8:	if (numlock) break;
 		case Core::Input::KI_UP:		MoveCursorVertical(-1, shift); break;
@@ -294,10 +314,10 @@ void WidgetTextInput::ProcessEvent(Core::Event& event)
 		case Core::Input::KI_DOWN:		MoveCursorVertical(1, shift); break;
 
 		case Core::Input::KI_NUMPAD7:	if (numlock) break;
-		case Core::Input::KI_HOME:		MoveCursorHorizontal(-cursor_character_index, shift); break;
+		case Core::Input::KI_HOME:		MoveCursorHorizontal(CursorMovement::BeginLine, shift); break;
 
 		case Core::Input::KI_NUMPAD1:	if (numlock) break;
-		case Core::Input::KI_END:		MoveCursorHorizontal(lines[cursor_line_index].content_length - cursor_character_index, shift); break;
+		case Core::Input::KI_END:		MoveCursorHorizontal(CursorMovement::EndLine, shift); break;
 
 		case Core::Input::KI_BACK:
 		{
@@ -352,16 +372,14 @@ void WidgetTextInput::ProcessEvent(Core::Event& event)
 		{
 			if (ctrl)
 			{
-				Core::WString clipboard_text;
+				Core::String clipboard_text;
 				Core::GetSystemInterface()->GetClipboardText(clipboard_text);
 
-				for (size_t i = 0; i < clipboard_text.size(); ++i)
+				// @performance: Can be made heaps faster.
+				for (auto it = Core::StringIteratorU8(clipboard_text); it; ++it)
 				{
-					if (max_length > 0 &&
-						(int)Core::StringUtilities::ToUCS2(GetElement()->GetAttribute< Rml::Core::String >("value", "")).size() > max_length)
-						break;
-
-					AddCharacter(clipboard_text[i]);
+					Core::Character code = *it;
+					AddCharacter(code);
 				}
 			}
 		}
@@ -386,9 +404,8 @@ void WidgetTextInput::ProcessEvent(Core::Event& event)
 			event.GetParameter< int >("alt_key", 0) == 0 &&
 			event.GetParameter< int >("meta_key", 0) == 0)
 		{
-			Rml::Core::word character = event.GetParameter< Rml::Core::word >("data", 0);
-			if (max_length < 0 || (int)Core::String(GetElement()->GetAttribute< Rml::Core::String >("value", "")).size() < max_length)
-				AddCharacter(character);
+			Rml::Core::Character character = event.GetParameter("data", Rml::Core::Character::Null);
+			AddCharacter(character);
 		}
 
 		ShowCursor(true);
@@ -425,6 +442,8 @@ void WidgetTextInput::ProcessEvent(Core::Event& event)
 			cursor_character_index = CalculateCharacterIndex(cursor_line_index, mouse_position.x);
 
 			UpdateAbsoluteCursor();
+			MoveCursorToCharacterBoundaries(false);
+
 			UpdateCursorPosition();
 			ideal_cursor_position = cursor_position.x;
 
@@ -442,21 +461,25 @@ void WidgetTextInput::ProcessEvent(Core::Event& event)
 }
 
 // Adds a new character to the string at the cursor position.
-bool WidgetTextInput::AddCharacter(Rml::Core::word character)
+bool WidgetTextInput::AddCharacter(Rml::Core::Character character)
 {
-	if (!IsCharacterValid(character))
+	if ((char32_t)character <= 127 && !IsCharacterValid(static_cast<char>(character)))
 		return false;
 
 	if (selection_length > 0)
 		DeleteSelection();
 
-	Core::WString value = Core::StringUtilities::ToUCS2(GetElement()->GetAttribute< Rml::Core::String >("value", ""));
-	value.insert(GetCursorIndex(), 1, character);
+	if (max_length >= 0 && GetLength() >= max_length)
+		return false;
 
-	edit_index += 1;
+	Core::String value = GetElement()->GetAttribute< Rml::Core::String >("value", "");
+	
+	Core::String insert = Core::StringUtilities::ToUTF8(character);
+	value.insert(GetCursorIndex(), insert);
 
-	Rml::Core::String utf8_value = Core::StringUtilities::ToUTF8(value);
-	GetElement()->SetAttribute("value", utf8_value);
+	edit_index += (int)insert.size();
+
+	GetElement()->SetAttribute("value", value);
 	DispatchChangeEvent();
 
 	UpdateSelection(false);
@@ -467,8 +490,11 @@ bool WidgetTextInput::AddCharacter(Rml::Core::word character)
 // Deletes a character from the string.
 bool WidgetTextInput::DeleteCharacter(bool back)
 {
-	// First, check if we have anything selected; if so, delete that first before we start delete
-	// individual characters.
+	// We set a selection of the next or previous character, and then delete it.
+	// If we already have a selection, we delete that first.
+	if (selection_length <= 0)
+		MoveCursorHorizontal(back ? CursorMovement::Left : CursorMovement::Right, true);
+
 	if (selection_length > 0)
 	{
 		DeleteSelection();
@@ -479,38 +505,14 @@ bool WidgetTextInput::DeleteCharacter(bool back)
 		return true;
 	}
 
-	Core::WString value = Core::StringUtilities::ToUCS2(GetElement()->GetAttribute< Rml::Core::String >("value", ""));
-
-	if (back)
-	{
-		if (GetCursorIndex() == 0)
-			return false;
-
-		value.erase(GetCursorIndex() - 1, 1);
-		edit_index -= 1;
-	}
-	else
-	{
-		if (GetCursorIndex() == (int) value.size())
-			return false;
-
-		value.erase(GetCursorIndex(), 1);
-	}
-
-	Rml::Core::String utf8_value = Core::StringUtilities::ToUTF8(value);
-	GetElement()->SetAttribute("value", utf8_value);
-	DispatchChangeEvent();
-
-	UpdateSelection(false);
-
-	return true;
+	return false;
 }
 
 // Copies the selection (if any) to the clipboard.
 void WidgetTextInput::CopySelection()
 {
 	const Core::String& value = GetElement()->GetAttribute< Rml::Core::String >("value", "");
-	const Core::WString snippet = Core::StringUtilities::ToUCS2(value.substr(selection_begin_index, selection_length));
+	const Core::String snippet = value.substr(selection_begin_index, selection_length);
 	Core::GetSystemInterface()->SetClipboardText(snippet);
 }
 
@@ -521,16 +523,86 @@ int WidgetTextInput::GetCursorIndex() const
 }
 
 // Moves the cursor along the current line.
-void WidgetTextInput::MoveCursorHorizontal(int distance, bool select)
+void WidgetTextInput::MoveCursorHorizontal(CursorMovement movement, bool select)
 {
-	absolute_cursor_index += distance;
+	const auto is_nonword_character = [](char c) -> bool {
+		return Core::StringUtilities::IsWhitespace(c) || (c >= '!' && c <= '@');
+	};
+
+	// Whether to seek forward or back to align to utf8 boundaries later.
+	bool seek_forward = false;
+
+	switch (movement)
+	{
+	case CursorMovement::BeginLine:
+		absolute_cursor_index -= cursor_character_index;
+		break;
+	case CursorMovement::PreviousWord:
+		if (cursor_character_index <= 1)
+		{
+			absolute_cursor_index -= 1;
+		}
+		else
+		{
+			bool whitespace_found = false;
+			const char* p_rend = lines[cursor_line_index].content.data();
+			const char* p_rbegin = p_rend + cursor_character_index;
+			const char* p = p_rbegin - 1;
+			for (; p > p_rend; --p)
+			{
+				bool is_whitespace = is_nonword_character(*p);
+				if(whitespace_found && !is_whitespace)
+					break;
+				else if(!whitespace_found && is_whitespace)
+					whitespace_found = true;
+			}
+			if (p != p_rend) ++p;
+			absolute_cursor_index += int(p - p_rbegin);
+		}
+		break;
+	case CursorMovement::Left:
+		absolute_cursor_index -= 1;
+		break;
+	case CursorMovement::Right:
+		seek_forward = true;
+		absolute_cursor_index += 1;
+		break;
+	case CursorMovement::NextWord:
+		if (cursor_character_index >= lines[cursor_line_index].content_length)
+		{
+			absolute_cursor_index += 1;
+		}
+		else
+		{
+			bool whitespace_found = false;
+			const char* p_begin = lines[cursor_line_index].content.data() + cursor_character_index;
+			const char* p_end = lines[cursor_line_index].content.data() + lines[cursor_line_index].content_length;
+			const char* p = p_begin;
+			for (; p < p_end; ++p)
+			{
+				bool is_whitespace = is_nonword_character(*p);
+				if (whitespace_found && !is_whitespace)
+					break;
+				else if (!whitespace_found && is_whitespace)
+					whitespace_found = true;
+			}
+			absolute_cursor_index += int(p - p_begin);
+		}
+		break;
+	case CursorMovement::EndLine:
+		absolute_cursor_index += lines[cursor_line_index].content_length - cursor_character_index;
+		break;
+	default:
+		break;
+	}
+	
 	absolute_cursor_index = Rml::Core::Math::Max(0, absolute_cursor_index);
 
 	UpdateRelativeCursor();
-	ideal_cursor_position = cursor_position.x;
+	MoveCursorToCharacterBoundaries(seek_forward);
 
+	ideal_cursor_position = cursor_position.x;
 	UpdateSelection(select);
-
 	ShowCursor(true);
 }
 
@@ -558,6 +630,9 @@ void WidgetTextInput::MoveCursorVertical(int distance, bool select)
 		cursor_character_index = CalculateCharacterIndex(cursor_line_index, ideal_cursor_position);
 
 	UpdateAbsoluteCursor();
+
+	MoveCursorToCharacterBoundaries(false);
+
 	UpdateCursorPosition();
 
 	if (update_ideal_cursor_position)
@@ -568,6 +643,25 @@ void WidgetTextInput::MoveCursorVertical(int distance, bool select)
 	ShowCursor(true);
 }
 
+void WidgetTextInput::MoveCursorToCharacterBoundaries(bool forward)
+{
+	const char* p_line_begin = lines[cursor_line_index].content.data();
+	const char* p_line_end = p_line_begin + lines[cursor_line_index].content_length;
+	const char* p_cursor = p_line_begin + cursor_character_index;
+	const char* p = p_cursor;
+
+	if (forward)
+		p = Core::StringUtilities::SeekForwardUTF8(p_cursor, p_line_end);
+	else
+		p = Core::StringUtilities::SeekBackwardUTF8(p_cursor, p_line_begin);
+
+	if (p != p_cursor)
+	{
+		absolute_cursor_index += int(p - p_cursor);
+		UpdateRelativeCursor();
+	}
+}
+
 // Updates the absolute cursor index from the relative cursor indices.
 void WidgetTextInput::UpdateAbsoluteCursor()
 {
@@ -626,25 +720,28 @@ int WidgetTextInput::CalculateLineIndex(float position)
 // Calculates the character index along a line under a specific horizontal position.
 int WidgetTextInput::CalculateCharacterIndex(int line_index, float position)
 {
-	int character_index = 0;
-	float line_width = 0;
-
-	while (character_index < lines[line_index].content_length)
+	int prev_offset = 0;
+	float prev_line_width = 0;
+	
+	for(auto it = Core::StringIteratorU8(lines[line_index].content, 0, lines[line_index].content_length); it; )
 	{
-		float next_line_width = (float) Core::ElementUtilities::GetStringWidth(text_element, lines[line_index].content.substr(0, character_index));
-		if (next_line_width > position)
+		++it;
+		int offset = (int)it.Offset();
+
+		float line_width = (float) Core::ElementUtilities::GetStringWidth(text_element, lines[line_index].content.substr(0, offset));
+		if (line_width > position)
 		{
-			if (position - line_width < next_line_width - position)
-				return Rml::Core::Math::Max(0, character_index - 1);
+			if (position - prev_line_width < line_width - position)
+				return prev_offset;
 			else
-				return character_index;
+				return offset;
 		}
 
-		line_width = next_line_width;
-		character_index++;
+		prev_line_width = line_width;
+		prev_offset = offset;
 	}
 
-	return character_index;
+	return prev_offset;
 }
 
 // Shows or hides the cursor.
@@ -786,8 +883,8 @@ Rml::Core::Vector2f WidgetTextInput::FormatText()
 		{
 			soft_return = true;
 
-			const Core::WString& text = text_element->GetText();
-			Core::WString orphan;
+			const Core::String& text = text_element->GetText();
+			Core::String orphan;
 			for (int i = 1; i >= 0; --i)
 			{
 				int index = line_begin + line.content_length + i;
@@ -819,7 +916,7 @@ Rml::Core::Vector2f WidgetTextInput::FormatText()
 		// Now that we have the string of characters appearing on the new line, we split it into
 		// three parts; the unselected text appearing before any selected text on the line, the
 		// selected text on the line, and any unselected text after the selection.
-		Core::WString pre_selection, selection, post_selection;
+		Core::String pre_selection, selection, post_selection;
 		GetLineSelection(pre_selection, selection, post_selection, line.content, line_begin);
 
 		// The pre-selected text is placed, if there is any (if the selection starts on or before
@@ -958,9 +1055,9 @@ void WidgetTextInput::DeleteSelection()
 {
 	if (selection_length > 0)
 	{
-		const Core::WString& value = Core::StringUtilities::ToUCS2( GetElement()->GetAttribute< Rml::Core::String >("value", "") );
+		const Core::String& value = GetElement()->GetAttribute< Rml::Core::String >("value", "");
 
-		Rml::Core::String new_value = Core::StringUtilities::ToUTF8(Core::WString(value.substr(0, selection_begin_index) + value.substr(selection_begin_index + selection_length)));
+		Rml::Core::String new_value = value.substr(0, selection_begin_index) + value.substr(selection_begin_index + selection_length);
 		GetElement()->SetAttribute("value", new_value);
 
 		// Move the cursor to the beginning of the old selection.
@@ -973,7 +1070,7 @@ void WidgetTextInput::DeleteSelection()
 }
 
 // Split one line of text into three parts, based on the current selection.
-void WidgetTextInput::GetLineSelection(Core::WString& pre_selection, Core::WString& selection, Core::WString& post_selection, const Core::WString& line, int line_begin)
+void WidgetTextInput::GetLineSelection(Core::String& pre_selection, Core::String& selection, Core::String& post_selection, const Core::String& line, int line_begin)
 {
 	// Check if we have any selection at all, and if so if the selection is on this line.
 	if (selection_length <= 0 ||

+ 17 - 8
Source/Controls/WidgetTextInput.h

@@ -66,6 +66,8 @@ public:
 	/// Returns the maximum length (in characters) of this text field.
 	/// @return The maximum number of characters allowed in this text field.
 	int GetMaxLength() const;
+	/// Returns the current length (in characters) of this text field.
+	int GetLength() const;
 
 	/// Update the colours of the selected text.
 	void UpdateSelectionColours();
@@ -92,7 +94,7 @@ protected:
 	/// Adds a new character to the string at the cursor position.
 	/// @param[in] character The character to add to the string.
 	/// @return True if the character was successfully added, false otherwise.
-	bool AddCharacter(Rml::Core::word character);
+	bool AddCharacter(Rml::Core::Character character);
 	/// Deletes a character from the string.
 	/// @param[in] backward True to delete a character behind the cursor, false for in front of the cursor.
 	/// @return True if a character was deleted, false otherwise.
@@ -100,7 +102,7 @@ protected:
 	/// Returns true if the given character is permitted in the input field, false if not.
 	/// @param[in] character The character to validate.
 	/// @return True if the character is allowed, false if not.
-	virtual bool IsCharacterValid(Rml::Core::word character) = 0;
+	virtual bool IsCharacterValid(char character) = 0;
 	/// Called when the user pressed enter.
 	virtual void LineBreak() = 0;
 
@@ -108,20 +110,25 @@ protected:
 	int GetCursorIndex() const;
 
 	/// Gets the parent element containing the widget.
-	Core::Element* GetElement();
+	Core::Element* GetElement() const;
 
 	/// Dispatches a change event to the widget's element.
 	void DispatchChangeEvent(bool linebreak = false);
 
 private:
+	enum class CursorMovement { BeginLine = -3, PreviousWord = -2, Left = -1, Right = 1, NextWord = 2, EndLine = 3 };
+	
 	/// Moves the cursor along the current line.
-	/// @param[in] x How far to move the cursor.
+	/// @param[in] movement Cursor movement operation.
 	/// @param[in] select True if the movement will also move the selection cursor, false if not.
-	void MoveCursorHorizontal(int distance, bool select);
+	void MoveCursorHorizontal(CursorMovement movement, bool select);
 	/// Moves the cursor up and down the text field.
 	/// @param[in] x How far to move the cursor.
 	/// @param[in] select True if the movement will also move the selection cursor, false if not.
 	void MoveCursorVertical(int distance, bool select);
+	// Move the cursor to utf-8 boundaries, in case it was moved into the middle of a multibyte character.
+	/// @param[in] forward True to seek forward, else back.
+	void MoveCursorToCharacterBoundaries(bool forward);
 
 	/// Updates the absolute cursor index from the relative cursor indices.
 	void UpdateAbsoluteCursor();
@@ -170,12 +177,12 @@ private:
 	/// @param[out] post_selection The section of unselected text after any selected text on the line. If there is no selection on the line, then this will be empty.
 	/// @param[in] line The text making up the line.
 	/// @param[in] line_begin The absolute index at the beginning of the line.
-	void GetLineSelection(Core::WString& pre_selection, Core::WString& selection, Core::WString& post_selection, const Core::WString& line, int line_begin);
+	void GetLineSelection(Core::String& pre_selection, Core::String& selection, Core::String& post_selection, const Core::String& line, int line_begin);
 
 	struct Line
 	{
 		// The contents of the line (including the trailing endline, if that terminated the line).
-		Core::WString content;
+		Core::String content;
 		// The length of the editable characters on the line (excluding any trailing endline).
 		int content_length;
 
@@ -194,10 +201,12 @@ private:
 	typedef std::vector< Line > LineList;
 	LineList lines;
 
+	// Length in number of characters.
 	int max_length;
 
+	// Indices in bytes: Should always be moved along UTF-8 start bytes.
 	int edit_index;
-
+	
 	int absolute_cursor_index;
 	int cursor_line_index;
 	int cursor_character_index;

+ 1 - 1
Source/Controls/WidgetTextInputMultiLine.cpp

@@ -42,7 +42,7 @@ WidgetTextInputMultiLine::~WidgetTextInputMultiLine()
 }
 
 // Returns true if the given character is permitted in the input field, false if not.
-bool WidgetTextInputMultiLine::IsCharacterValid(Rml::Core::word character)
+bool WidgetTextInputMultiLine::IsCharacterValid(char character)
 {
 	return character != '\t';
 }

+ 1 - 1
Source/Controls/WidgetTextInputMultiLine.h

@@ -50,7 +50,7 @@ protected:
 	/// Returns true if the given character is permitted in the input field, false if not.
 	/// @param[in] character The character to validate.
 	/// @return True if the character is allowed, false if not.
-	bool IsCharacterValid(Rml::Core::word character) override;
+	bool IsCharacterValid(char character) override;
 	/// Called when the user pressed enter.
 	void LineBreak() override;		
 };

+ 1 - 1
Source/Controls/WidgetTextInputSingleLine.cpp

@@ -51,7 +51,7 @@ void WidgetTextInputSingleLine::SetValue(const Core::String& value)
 }
 
 // Returns true if the given character is permitted in the input field, false if not.
-bool WidgetTextInputSingleLine::IsCharacterValid(Rml::Core::word character)
+bool WidgetTextInputSingleLine::IsCharacterValid(char character)
 {
 	return character != '\t' && character != '\n' && character != '\r';
 }

+ 1 - 1
Source/Controls/WidgetTextInputSingleLine.h

@@ -54,7 +54,7 @@ protected:
 	/// Returns true if the given character is permitted in the input field, false if not.
 	/// @param[in] character The character to validate.
 	/// @return True if the character is allowed, false if not.
-	bool IsCharacterValid(Rml::Core::word character) override;
+	bool IsCharacterValid(char character) override;
 	/// Called when the user pressed enter.
 	void LineBreak() override;
 

+ 1 - 1
Source/Controls/WidgetTextInputSingleLinePassword.cpp

@@ -45,7 +45,7 @@ void WidgetTextInputSingleLinePassword::SetValue(const Core::String& value)
 {
 	Core::String sanitised_value(value);
 	SanitiseValue(sanitised_value);
-	WidgetTextInput::SetValue(Core::String(sanitised_value.size(), (Rml::Core::word) '*'));
+	WidgetTextInput::SetValue(Core::String(sanitised_value.size(), '*'));
 }
 
 }

+ 0 - 153
Source/Core/BitmapFont/BitmapFontDefinitions.h

@@ -1,153 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef BITMAPFONTDEFINITIONS_H
-#define BITMAPFONTDEFINITIONS_H
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include <RmlUi/Core/Header.h>
-#include <RmlUi/Core/Types.h>
-#include <RmlUi/Core/Dictionary.h>
-#include <set>
-
-namespace Rml {
-namespace Core {
-namespace BitmapFont {
-
-	struct FontInfo
-	{
-		String FamilyName;
-		String Source;
-		String BitmapSource;
-		int Size;
-		Style::FontStyle Style;
-		Style::FontWeight Weight;
-	};
-
-	struct CharacterCommonInfo
-	{
-		int LineHeight;
-		int BaseLine;
-		int ScaleWidth;
-		int ScaleHeight;
-		int CharacterCount;
-		int KerningCount;
-	};
-
-	struct CharacterInfo
-	{
-		int Id;
-		int X;
-		int Y;
-		int Width;
-		int Height;
-		int XOffset;
-		int YOffset;
-		int Advance;
-	};
-
-	struct KerningInfo
-	{
-		int FirstCharacterId;
-		int SecondCharacterId;
-		int KerningAmount;
-	};
-
-	class BitmapFontDefinitions
-	{
-	public:
-		FontInfo Face;
-		CharacterCommonInfo CommonCharactersInfo;
-		CharacterInfo *CharactersInfo;
-		KerningInfo *KerningsInfo;
-
-		int BM_Helper_GetCharacterTableIndex( int unicode_code )
-		{
-			return BinarySearch( unicode_code, 0, CommonCharactersInfo.CharacterCount );
-		}
-
-		int BM_Helper_GetXKerning( int left_uni_id, int right_uni_id )
-		{
-			for ( int i = 0; i < this->CommonCharactersInfo.KerningCount; i++ )
-			{
-				if ( this->KerningsInfo[i].FirstCharacterId == left_uni_id && this->KerningsInfo[i].SecondCharacterId == right_uni_id )
-				{
-					return this->KerningsInfo[i].KerningAmount;
-				}
-			}
-
-			return 0;
-		}
-
-	private:
-
-		int BinarySearch( int unicode_code, int min_index, int max_index )
-		{
-			if ( abs( max_index - min_index ) <= 1 )
-			{
-				if ( this->CharactersInfo[ min_index ].Id == unicode_code )
-				{
-					return min_index;
-				}
-				else if ( this->CharactersInfo[ max_index ].Id == unicode_code )
-				{
-					return max_index;
-				}
-				else
-				{
-					return -1;
-				}
-			}
-			else
-			{
-				int mid_index = ( min_index + max_index ) / 2;
-
-				if ( this->CharactersInfo[ mid_index ].Id == unicode_code )
-				{
-					return mid_index;
-				}
-				else if ( this->CharactersInfo[ mid_index ].Id > unicode_code )
-				{
-					return BinarySearch( unicode_code, min_index, mid_index );
-				}
-				else
-				{
-					return BinarySearch( unicode_code, mid_index, max_index );
-				}
-			}
-		}
-	};
-
-}
-}
-}
-
-#endif
-
-#endif

+ 0 - 129
Source/Core/BitmapFont/FontFace.cpp

@@ -1,129 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include "precompiled.h"
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "FontFace.h"
-#include "FontFaceHandle.h"
-#include <RmlUi/Core/Log.h>
-
-namespace Rml {
-namespace Core {
-
-BitmapFont::FontFace::FontFace(BitmapFontDefinitions *_face, Style::FontStyle _style, Style::FontWeight _weight, bool _release_stream) : Rml::Core::FontFace(_style, _weight, _release_stream)
-{
-	face = _face;
-}
-
-BitmapFont::FontFace::~FontFace()
-{
-	ReleaseFace();
-}
-
-// Returns a handle for positioning and rendering this face at the given size.
-SharedPtr<Rml::Core::FontFaceHandleDefault> BitmapFont::FontFace::GetHandle(const String& _raw_charset, int size)
-{
-	UnicodeRangeList charset;
-
-	HandleMap::iterator iterator = handles.find(size);
-	if (iterator != handles.end())
-	{
-		const HandleList& handles = (*iterator).second;
-
-		// Check all the handles if their charsets match the requested one exactly (ie, were specified by the same
-		// string).
-		String raw_charset(_raw_charset);
-		for (size_t i = 0; i < handles.size(); ++i)
-		{
-			if (handles[i]->GetRawCharset() == _raw_charset)
-			{
-				return handles[i];
-			}
-		}
-
-		// Check all the handles if their charsets contain the requested charset.
-		if (!UnicodeRange::BuildList(charset, raw_charset))
-		{
-			Log::Message(Log::LT_ERROR, "Invalid font charset '%s'.", _raw_charset.c_str());
-			return nullptr;
-		}
-
-		for (size_t i = 0; i < handles.size(); ++i)
-		{
-			bool range_contained = true;
-
-			const UnicodeRangeList& handle_charset = handles[i]->GetCharset();
-			for (size_t j = 0; j < charset.size() && range_contained; ++j)
-			{
-				if (!charset[j].IsContained(handle_charset))
-					range_contained = false;
-			}
-
-			if (range_contained)
-			{
-				return handles[i];
-			}
-		}
-	}
-
-	// See if this face has been released.
-	if (!face)
-	{
-		Log::Message(Log::LT_WARNING, "Font face has been released, unable to generate new handle.");
-		return nullptr;
-	}
-
-	// Construct and initialise the new handle.
-	auto handle = std::make_shared<BitmapFont::FontFaceHandle>();
-	if (!handle->Initialise(face, _raw_charset, size))
-	{
-		return nullptr;
-	}
-
-	// Save the handle, and add a reference for the callee. The initial reference will be removed when the font face
-	// releases it.
-	if (iterator != handles.end())
-		(*iterator).second.push_back(handle);
-	else
-		handles[size] = HandleList(1, handle);
-
-	return handle;
-}
-
-// Releases the face's structure.
-void BitmapFont::FontFace::ReleaseFace()
-{
-	delete face;
-}
-
-}
-}
-
-#endif

+ 0 - 73
Source/Core/BitmapFont/FontFace.h

@@ -1,73 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef RMLUICOREBITMAPFONTFACE_H
-#define RMLUICOREBITMAPFONTFACE_H
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "../FontFace.h"
-#include "BitmapFontDefinitions.h"
-
-namespace Rml {
-namespace Core {
-namespace BitmapFont {
-
-class FontFaceHandleDefault;
-
-/**
-	@author Peter Curry
- */
-
-class FontFace : public Rml::Core::FontFace
-{
-public:
-	FontFace(BitmapFontDefinitions *_face, Style::FontStyle style, Style::FontWeight weight, bool release_stream);
-	~FontFace();
-
-	/// Returns a handle for positioning and rendering this face at the given size.
-	/// @param[in] charset The set of characters in the handle, as a comma-separated list of unicode ranges.
-	/// @param[in] size The size of the desired handle, in points.
-	/// @return The shared font handle.
-	SharedPtr<Rml::Core::FontFaceHandleDefault> GetHandle(const String& charset, int size) override;
-
-	/// Releases the face's FreeType face structure. This will mean handles for new sizes cannot be constructed,
-	/// but existing ones can still be fetched.
-	void ReleaseFace() override;
-
-private:
-	BitmapFontDefinitions *face;
-};
-
-}
-}
-}
-
-#endif
-
-#endif

+ 0 - 185
Source/Core/BitmapFont/FontFaceHandle.cpp

@@ -1,185 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include "precompiled.h"
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "FontFaceHandle.h"
-#include "FontFaceLayer.h"
-#include <algorithm>
-#include "../TextureLayout.h"
-
-namespace Rml {
-namespace Core {
-
-BitmapFont::FontFaceHandle::FontFaceHandle()
-{
-	bm_face = nullptr;
-	texture_width = 0;
-	texture_height = 0;
-}
-
-BitmapFont::FontFaceHandle::~FontFaceHandle()
-{
-}
-
-// Initialises the handle so it is able to render text.
-bool BitmapFont::FontFaceHandle::Initialise(BitmapFontDefinitions *_bm_face, const String& _charset, int _size)
-{
-	bm_face = _bm_face;
-	size = _size;
-	line_height = _size;
-	texture_width = bm_face->CommonCharactersInfo.ScaleWidth;
-	texture_height = bm_face->CommonCharactersInfo.ScaleHeight;
-	raw_charset = _charset;
-
-	// Construct proper path to texture
-	URL fnt_source = bm_face->Face.Source;
-	URL bitmap_source = bm_face->Face.BitmapSource;
-	if(bitmap_source.GetPath().empty())
-	{
-		texture_source = fnt_source.GetPath() + bitmap_source.GetFileName();
-		if(!bitmap_source.GetExtension().empty())
-		{
-			texture_source += "." + bitmap_source.GetExtension();
-		}
-	}
-	else
-	{
-		texture_source = bitmap_source.GetPathedFileName();
-	}
-
-	if (!UnicodeRange::BuildList(charset, raw_charset))
-	{
-		Log::Message(Log::LT_ERROR, "Invalid font charset '%s'.", raw_charset.c_str());
-		return false;
-	}
-
-	// Construct the list of the characters specified by the charset.
-	for (size_t i = 0; i < charset.size(); ++i)
-		BuildGlyphMap(bm_face, charset[i]);
-
-	// Generate the metrics for the handle.
-	GenerateMetrics(bm_face);
-
-	// Generate the default layer and layer configuration.
-	base_layer = GenerateLayer(nullptr);
-	layer_configurations.push_back(LayerConfiguration());
-	layer_configurations.back().push_back(base_layer);
-
-	return true;
-}
-
-void BitmapFont::FontFaceHandle::GenerateMetrics(BitmapFontDefinitions *bm_face)
-{
-	line_height = bm_face->CommonCharactersInfo.LineHeight;
-	baseline = bm_face->CommonCharactersInfo.BaseLine;
-
-	underline_position = (float)line_height - bm_face->CommonCharactersInfo.BaseLine;
-	baseline += int( underline_position / 1.6f );
-	underline_thickness = 1.0f;
-
-	average_advance = 0;
-	for (FontGlyphList::iterator i = glyphs.begin(); i != glyphs.end(); ++i)
-		average_advance += i->advance;
-
-	// Bring the total advance down to the average advance, but scaled up 10%, just to be on the safe side.
-	average_advance = Math::RealToInteger((float) average_advance / (glyphs.size() * 0.9f));
-
-	// Determine the x-height of this font face.
-	word x = (word) 'x';
-	int index = bm_face->BM_Helper_GetCharacterTableIndex( x );// FT_Get_Char_Index(ft_face, x);
-
-	if ( index >= 0)
-		x_height = bm_face->CharactersInfo[ index ].Height;
-	else
-		x_height = 0;
-}
-
-void BitmapFont::FontFaceHandle::BuildGlyphMap(BitmapFontDefinitions *bm_face, const UnicodeRange& unicode_range)
-{
-	glyphs.resize(unicode_range.max_codepoint + 1);
-
-	for (word character_code = (word) (Math::Max< unsigned int >(unicode_range.min_codepoint, 32)); character_code <= unicode_range.max_codepoint; ++character_code)
-	{
-		int index = bm_face->BM_Helper_GetCharacterTableIndex( character_code );
-
-		if ( index < 0 )
-		{
-			continue;
-		}
-
-		FontGlyph glyph;
-		glyph.character = character_code;
-		BuildGlyph(glyph, &bm_face->CharactersInfo[ index ] );
-		glyphs[character_code] = glyph;
-	}
-}
-
-void BitmapFont::FontFaceHandle::BuildGlyph(FontGlyph& glyph, CharacterInfo *bm_glyph)
-{
-	// Set the glyph's dimensions.
-	glyph.dimensions.x = bm_glyph->Width;
-	glyph.dimensions.y = bm_glyph->Height;
-
-	// Set the glyph's bearing.
-	glyph.bearing.x = bm_glyph->XOffset;
-	glyph.bearing.y = bm_glyph->YOffset;
-
-	// Set the glyph's advance.
-	glyph.advance = bm_glyph->Advance;
-
-	// Set the glyph's bitmap position.
-	glyph.bitmap_dimensions.x = bm_glyph->X;
-	glyph.bitmap_dimensions.y = bm_glyph->Y;
-
-	glyph.bitmap_data = nullptr;
-}
-
-int BitmapFont::FontFaceHandle::GetKerning(word lhs, word rhs) const
-{
-	if( bm_face != nullptr)
-	{
-		return bm_face->BM_Helper_GetXKerning(lhs, rhs);
-	}
-
-	return 0;
-}
-
-Rml::Core::FontFaceLayer* BitmapFont::FontFaceHandle::CreateNewLayer()
-{
-	return new BitmapFont::FontFaceLayer();
-}
-
-
-}
-}
-
-#endif
-

+ 0 - 98
Source/Core/BitmapFont/FontFaceHandle.h

@@ -1,98 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef RMLUICOREBITMAPFONTFONTFACEHANDLE_H
-#define RMLUICOREBITMAPFONTFONTFACEHANDLE_H
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "../UnicodeRange.h"
-#include "../../../Include/RmlUi/Core/FontEffect.h"
-#include "../../../Include/RmlUi/Core/FontGlyph.h"
-#include "../../../Include/RmlUi/Core/Geometry.h"
-#include "../../../Include/RmlUi/Core/Texture.h"
-#include "../FontFaceHandleDefault.h"
-#include "BitmapFontDefinitions.h"
-
-namespace Rml {
-namespace Core {
-namespace BitmapFont {
-
-/**
-	@author Peter Curry
- */
-
-class FontFaceHandle : public Rml::Core::FontFaceHandleDefault
-{
-public:
-	FontFaceHandle();
-	virtual ~FontFaceHandle();
-
-	/// Initialises the handle so it is able to render text.
-	bool Initialise(BitmapFontDefinitions *bm_face, const String& charset, int size);
-
-	const String & GetTextureSource() const
-	{
-		return texture_source;
-	}
-
-	unsigned int GetTextureWidth() const
-	{
-		return texture_width;
-	}
-
-	unsigned int GetTextureHeight() const
-	{
-		return texture_height;
-	}
-
-protected:
-	Rml::Core::FontFaceLayer* CreateNewLayer() override;
-
-private:
-	void GenerateMetrics(BitmapFontDefinitions *bm_face);
-
-	void BuildGlyphMap(BitmapFontDefinitions *bm_face, const UnicodeRange& unicode_range);
-	void BuildGlyph(FontGlyph& glyph, CharacterInfo *ft_glyph);
-
-	int GetKerning(word lhs, word rhs) const override;
-
-	BitmapFontDefinitions * bm_face;
-	String texture_source;
-	String texture_directory;
-	unsigned int texture_width;
-	unsigned int texture_height;
-};
-
-}
-}
-}
-
-#endif
-
-#endif

+ 0 - 131
Source/Core/BitmapFont/FontFaceLayer.cpp

@@ -1,131 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include "precompiled.h"
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "FontFaceLayer.h"
-#include "FontFaceHandle.h"
-
-namespace Rml {
-namespace Core {
-
-BitmapFont::FontFaceLayer::FontFaceLayer() : Rml::Core::FontFaceLayer()
-{
-	handle = nullptr;
-	effect = nullptr;
-}
-
-BitmapFont::FontFaceLayer::~FontFaceLayer()
-{
-}
-
-// Generates the character and texture data for the layer.
-bool BitmapFont::FontFaceLayer::Initialise(const Rml::Core::FontFaceHandleDefault* _handle, SharedPtr<const FontEffect> _effect, const Rml::Core::FontFaceLayer* clone, bool deep_clone)
-{
-	(void)(_effect);
-
-	Rml::Core::BitmapFont::FontFaceHandle
-		* bm_font_face_handle;
-
-	handle = _handle;
-
-	bm_font_face_handle = ( Rml::Core::BitmapFont::FontFaceHandle * ) handle;
-
-	const FontGlyphList& glyphs = handle->GetGlyphs();
-
-	// Clone the geometry and textures from the clone layer.
-	if (clone != nullptr)
-	{
-		// Copy the cloned layer's characters.
-		characters = clone->characters;
-
-		// Copy (and reference) the cloned layer's textures.
-		for (size_t i = 0; i < clone->textures.size(); ++i)
-			textures.push_back(clone->textures[i]);
-	}
-	else
-	{
-		// Load texture from file
-		Texture texture;
-		if (!texture.Load( bm_font_face_handle->GetTextureSource() ))
-			return false;
-
-		textures.push_back(texture);
-
-		// Initialise the texture layout for the glyphs.
-		characters.resize(glyphs.size(), Character());
-		for (FontGlyphList::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i)
-		{
-			const FontGlyph& glyph = *i;
-
-			if(glyph.dimensions.x <= 0 || glyph.dimensions.y <= 0)
-				continue;
-
-			Vector2i glyph_origin( glyph.bitmap_dimensions.x, glyph.bitmap_dimensions.y ); // position in texture
-			Vector2i glyph_dimensions = glyph.dimensions; // size of char
-
-			Character character;
-			character.origin = Vector2f((float) (glyph.bearing.x), (float) (glyph.bearing.y) - handle->GetBaseline()*3 );
-			character.dimensions = Vector2f((float) glyph.dimensions.x, (float) glyph.dimensions.y);
-
-			// Set the character's texture index.
-			character.texture_index = 0;
-
-			// Generate the character's texture coordinates.
-			character.texcoords[0].x = float(glyph_origin.x) / float(bm_font_face_handle->GetTextureWidth());
-			character.texcoords[0].y = float(glyph_origin.y) / float(bm_font_face_handle->GetTextureHeight());
-			character.texcoords[1].x = float(glyph_origin.x + character.dimensions.x) / float(bm_font_face_handle->GetTextureWidth());
-			character.texcoords[1].y = float(glyph_origin.y + character.dimensions.y) / float(bm_font_face_handle->GetTextureHeight());
-
-			characters[glyph.character] = character;
-
-			// Add the character's dimensions into the texture layout engine.
-			texture_layout.AddRectangle(glyph.character, glyph_dimensions);
-		}
-
-		// Generate the texture layout; this will position the glyph rectangles efficiently and
-		// allocate the texture data ready for writing.
-		if (!texture_layout.GenerateLayout(512))
-			return false;
-
-	}
-	return true;
-}
-
-// Generates the texture data for a layer (for the texture database).
-bool BitmapFont::FontFaceLayer::GenerateTexture(const byte*& texture_data, Vector2i& texture_dimensions, int texture_id)
-{
-	return true;
-}
-
-}
-}
-
-#endif

+ 0 - 82
Source/Core/BitmapFont/FontFaceLayer.h

@@ -1,82 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef RMLUICOREBITMAPFONTFACELAYER_H
-#define RMLUICOREBITMAPFONTFACELAYER_H
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include <RmlUi/Core/Header.h>
-#include <RmlUi/Core/FontGlyph.h>
-#include <RmlUi/Core/Geometry.h>
-#include <RmlUi/Core/GeometryUtilities.h>
-#include "../FontFaceLayer.h"
-
-namespace Rml {
-namespace Core {
-
-	class TextureLayout;
-
-namespace BitmapFont {
-
-/**
-	A textured layer stored as part of a font face handle. Each handle will have at least a base
-	layer for the standard font. Further layers can be added to allow to rendering of text effects.
-	@author Peter Curry
- */
-
-class FontFaceLayer : public Rml::Core::FontFaceLayer
-{
-public:
-	FontFaceLayer();
-	virtual ~FontFaceLayer();
-
-	/// Generates the character and texture data for the layer.
-	/// @param[in] handle The handle generating this layer.
-	/// @param[in] effect The effect to initialise the layer with.
-	/// @param[in] clone The layer to optionally clone geometry and texture data from.
-	/// @param[in] deep_clone If true, the clones geometry will be completely cloned and the effect will have no option to affect even the glyph origins.
-	/// @return True if the layer was generated successfully, false if not.
-	bool Initialise(const Rml::Core::FontFaceHandleDefault* handle, SharedPtr<const FontEffect> effect, const Rml::Core::FontFaceLayer* clone = nullptr, bool deep_clone = false) override;
-
-	/// Generates the texture data for a layer (for the texture database).
-	/// @param[out] texture_data The pointer to be set to the generated texture data.
-	/// @param[out] texture_dimensions The dimensions of the texture.
-	/// @param[in] glyphs The glyphs required by the font face handle.
-	/// @param[in] texture_id The index of the texture within the layer to generate.
-	bool GenerateTexture(const byte*& texture_data, Vector2i& texture_dimensions, int texture_id) override;
-
-};
-
-}
-}
-}
-
-#endif
-
-#endif

+ 0 - 59
Source/Core/BitmapFont/FontFamily.cpp

@@ -1,59 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include "precompiled.h"
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "FontFamily.h"
-#include "FontFace.h"
-
-namespace Rml {
-namespace Core {
-
-BitmapFont::FontFamily::FontFamily(const String& name) : Rml::Core::FontFamily(name)
-{
-}
-
-BitmapFont::FontFamily::~FontFamily()
-{
-}
-
-// Adds a new face to the family.
-bool BitmapFont::FontFamily::AddFace( void *bm_face, Style::FontStyle style, Style::FontWeight weight, bool release_stream)
-{
-	Rml::Core::FontFace* face = new BitmapFont::FontFace((BitmapFontDefinitions*)bm_face, style, weight, release_stream);
-	font_faces.push_back(face);
-
-	return true;
-}
-
-}
-}
-
-#endif

+ 0 - 69
Source/Core/BitmapFont/FontFamily.h

@@ -1,69 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef RMLUICOREBITMAPFONTFAMILY_H
-#define RMLUICOREBITMAPFONTFAMILY_H
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "../FontFamily.h"
-#include "BitmapFontDefinitions.h"
-
-namespace Rml {
-namespace Core {
-
-class FontFace;
-
-namespace BitmapFont {
-
-/**
-	@author Peter Curry
- */
-
-class FontFamily : public Rml::Core::FontFamily
-{
-public:
-	FontFamily(const String& name);
-	~FontFamily();
-
-	/// Adds a new face to the family.
-	/// @param[in] ft_face The previously loaded FreeType face.
-	/// @param[in] style The style of the new face.
-	/// @param[in] weight The weight of the new face.
-	/// @param[in] release_stream True if the application must free the face's memory stream.
-	/// @return True if the face was loaded successfully, false otherwise.
-	bool AddFace( void *bm_face, Style::FontStyle style, Style::FontWeight weight, bool release_stream) override;
-};
-
-}
-}
-}
-
-#endif
-
-#endif

+ 0 - 121
Source/Core/BitmapFont/FontParser.cpp

@@ -1,121 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include "precompiled.h"
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "FontParser.h"
-
-namespace Rml {
-namespace Core {
-
-BitmapFont::FontParser::FontParser( BitmapFontDefinitions *face )
-	: BaseXMLParser()
-{
-	bm_face = face;
-	char_id = 0;
-	kern_id = 0;
-}
-
-BitmapFont::FontParser::~FontParser()
-{
-}
-
-// Called when the parser finds the beginning of an element tag.
-void BitmapFont::FontParser::HandleElementStart(const String& name, const XMLAttributes& attributes)
-{
-	if ( name == "info" )
-	{
-		bm_face->Face.FamilyName = Get(attributes, "face", String());
-		bm_face->Face.Size = Get(attributes, "size", 0);
-		bm_face->Face.Weight = Get(attributes, "bold", false ) ? Style::FontWeight::Bold : Style::FontWeight::Normal;
-		bm_face->Face.Style = Get(attributes, "italic", false ) ? Style::FontStyle::Italic : Style::FontStyle::Normal;
-		bm_face->Face.BitmapSource = Get(attributes, "src", String());
-	}
-	else if ( name == "common" )
-	{
-		bm_face->CommonCharactersInfo.LineHeight = Get(attributes, "lineHeight", 0);
-		bm_face->CommonCharactersInfo.BaseLine = Get(attributes, "base", 0) * -1;
-		bm_face->CommonCharactersInfo.ScaleWidth = Get(attributes, "scaleW", 0);
-		bm_face->CommonCharactersInfo.ScaleHeight = Get(attributes, "scaleH", 0);
-		bm_face->CommonCharactersInfo.CharacterCount = 0;
-		bm_face->CommonCharactersInfo.KerningCount = 0;
-	}
-	else if ( name == "chars" )
-	{
-		bm_face->CommonCharactersInfo.CharacterCount = Get(attributes, "count", 0);
-		// Memory @leak ?
-		bm_face->CharactersInfo = new BitmapFont::CharacterInfo[ Get(attributes, "count", 0) ];
-	}
-	else if ( name == "char" )
-	{
-		bm_face->CharactersInfo[ char_id ].Id = Get(attributes, "id", 0);
-		bm_face->CharactersInfo[ char_id ].X = Get(attributes, "x", 0); //The left position of the character image in the texture.
-		bm_face->CharactersInfo[ char_id ].Y = Get(attributes, "y", 0); //The top position of the character image in the texture.
-		bm_face->CharactersInfo[ char_id ].Width = Get(attributes, "width", 0); //The width of the character image in the texture.
-		bm_face->CharactersInfo[ char_id ].Height = Get(attributes, "height", 0); //The height of the character image in the texture.
-		bm_face->CharactersInfo[ char_id ].XOffset = Get(attributes, "xoffset", 0);
-		bm_face->CharactersInfo[ char_id ].YOffset = Get(attributes, "yoffset", 0);
-		bm_face->CharactersInfo[ char_id ].Advance = Get(attributes, "xadvance", 0);
-
-		char_id++;
-	}
-	else if ( name == "kernings" )
-	{
-		bm_face->CommonCharactersInfo.KerningCount = Get(attributes, "count", 0);
-		// Memory @leak ?
-		bm_face->KerningsInfo = new BitmapFont::KerningInfo[ Get(attributes, "count", 0) ];
-	}
-	else if ( name == "kerning" )
-	{
-		bm_face->KerningsInfo[ kern_id ].FirstCharacterId = Get(attributes, "first", 0);
-		bm_face->KerningsInfo[ kern_id ].SecondCharacterId = Get(attributes, "second", 0);
-		bm_face->KerningsInfo[ kern_id ].KerningAmount = Get(attributes, "amount", 0);
-
-		kern_id++;
-	}
-}
-
-// Called when the parser finds the end of an element tag.
-void BitmapFont::FontParser::HandleElementEnd(const String& RMLUI_UNUSED_PARAMETER(name))
-{
-	RMLUI_UNUSED(name);
-}
-
-// Called when the parser encounters data.
-void BitmapFont::FontParser::HandleData(const String& RMLUI_UNUSED_PARAMETER(data))
-{
-	RMLUI_UNUSED(data);
-}
-
-}
-}
-
-#endif
-

+ 0 - 72
Source/Core/BitmapFont/FontParser.h

@@ -1,72 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef BITMAPFONTPARSER_H
-#define BITMAPFONTPARSER_H
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include <RmlUi/Core/Header.h>
-#include <RmlUi/Core/Types.h>
-#include <RmlUi/Core/Dictionary.h>
-#include "BitmapFontDefinitions.h"
-
-namespace Rml {
-namespace Core {
-namespace BitmapFont {
-
-/**
-	@author Peter Curry
- */
-
-class FontParser : public BaseXMLParser
-{
-public:
-	FontParser( BitmapFontDefinitions *face );
-	virtual ~FontParser();
-
-	/// Called when the parser finds the beginning of an element tag.
-	void HandleElementStart(const String& name, const XMLAttributes& attributes) override;
-	/// Called when the parser finds the end of an element tag.
-	void HandleElementEnd(const String& name) override;
-	/// Called when the parser encounters data.
-	void HandleData(const String& data) override;
-
-private:
-	FontParser();
-	BitmapFontDefinitions *bm_face;
-	int char_id;
-	int kern_id;
-};
-
-}
-}
-}
-#endif
-
-#endif

+ 0 - 174
Source/Core/BitmapFont/FontProvider.cpp

@@ -1,174 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include "precompiled.h"
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "FontProvider.h"
-#include "FontFaceHandle.h"
-#include "../FontDatabaseDefault.h"
-#include <RmlUi/Core/StreamMemory.h>
-#include "FontFamily.h"
-#include <RmlUi/Core.h>
-#include "BitmapFontDefinitions.h"
-#include "FontParser.h"
-
-namespace Rml {
-namespace Core {
-
-BitmapFont::FontProvider* BitmapFont::FontProvider::instance = nullptr;
-
-BitmapFont::FontProvider::FontProvider()
-{
-	RMLUI_ASSERT(instance == nullptr);
-	instance = this;
-}
-
-BitmapFont::FontProvider::~FontProvider()
-{
-	RMLUI_ASSERT(instance == this);
-	instance = nullptr;
-}
-
-bool BitmapFont::FontProvider::Initialise()
-{
-	if (instance == nullptr)
-	{
-		new FontProvider();
-
-		FontDatabaseDefault::AddFontProvider(instance);
-	}
-
-	return true;
-}
-
-void BitmapFont::FontProvider::Shutdown()
-{
-	if (instance != nullptr)
-	{
-		FontDatabaseDefault::RemoveFontProvider(instance);
-		delete instance;
-		instance = nullptr;
-	}
-}
-
-// Adds a new font face to the database, ignoring any family, style and weight information stored in the face itself.
-bool BitmapFont::FontProvider::LoadFontFace(const String& file_name)
-{
-	BitmapFont::BitmapFontDefinitions *bm_font = (BitmapFont::BitmapFontDefinitions*) instance->LoadFace(file_name);
-
-	if (bm_font == nullptr)
-	{
-		Log::Message(Log::LT_ERROR, "Failed to load font face from %s.", file_name.c_str());
-		return false;
-	}
-
-	Style::FontStyle style = bm_font->Face.Style;
-	Style::FontWeight weight = bm_font->Face.Weight;
-
-	if (instance->AddFace(bm_font, bm_font->Face.FamilyName, style, weight, true))
-	{
-		Log::Message(Log::LT_INFO, "Loaded font face %s (from %s).", bm_font->Face.FamilyName.c_str(), file_name.c_str());
-		return true;
-	}
-	else
-	{
-		Log::Message(Log::LT_ERROR, "Failed to load font face %s (from %s).", bm_font->Face.FamilyName.c_str(), file_name.c_str());
-		return false;
-	}
-
-	return true;
-}
-
-// Adds a loaded face to the appropriate font family.
-bool BitmapFont::FontProvider::AddFace(void* face, const String& family, Style::FontStyle style, Style::FontWeight weight, bool release_stream)
-{
-	String family_lower = StringUtilities::ToLower(family);
-	Rml::Core::FontFamily* font_family = nullptr;
-	FontFamilyMap::iterator iterator = instance->font_families.find(family_lower);
-	if (iterator != instance->font_families.end())
-		font_family = (*iterator).second;
-	else
-	{
-		font_family = new FontFamily(family_lower);
-		instance->font_families[family_lower] = font_family;
-	}
-
-	return font_family->AddFace((BitmapFontDefinitions *) face, style, weight, release_stream);
-}
-
-// Loads a FreeType face.
-void* BitmapFont::FontProvider::LoadFace(const String& file_name)
-{
-	BitmapFont::BitmapFontDefinitions *bm_face = new BitmapFont::BitmapFontDefinitions();
-	BitmapFont::FontParser parser( bm_face );
-
-	FileInterface* file_interface = GetFileInterface();
-	FileHandle handle = file_interface->Open(file_name);
-
-	if (!handle)
-	{
-		return nullptr;
-	}
-
-	size_t length = file_interface->Length(handle);
-
-	byte* buffer = new byte[length];
-	file_interface->Read(buffer, length, handle);
-	file_interface->Close(handle);
-
-	StreamMemory* stream = new StreamMemory( buffer, length );
-	stream->SetSourceURL( file_name );
-
-	parser.Parse( stream );
-
-	bm_face->Face.Source = file_name;
-	return bm_face;
-}
-
-// Loads a FreeType face from memory.
-void* BitmapFont::FontProvider::LoadFace(const byte* data, int data_length, const String& source, bool local_data)
-{
-	URL file_url = source + ".fnt";
-
-	BitmapFont::BitmapFontDefinitions *bm_face = new BitmapFont::BitmapFontDefinitions();
-	BitmapFont::FontParser parser( bm_face );
-	StreamMemory* stream = new StreamMemory( data, data_length );
-	stream->SetSourceURL( file_url );
-
-	parser.Parse( stream );
-
-	bm_face->Face.Source = file_url.GetPathedFileName();
-	return bm_face;
-}
-
-}
-}
-
-#endif

+ 0 - 85
Source/Core/BitmapFont/FontProvider.h

@@ -1,85 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef RMLUICOREBITMAPFONTFONTPROVIDER_H
-#define RMLUICOREBITMAPFONTFONTPROVIDER_H
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include <RmlUi/Core/StringUtilities.h>
-#include "../FontProvider.h"
-
-namespace Rml {
-namespace Core {
-
-
-class FontEffect;
-class PropertyDictionary;
-
-namespace BitmapFont {
-
-class FontFamily;
-
-/**
-    The font database contains all font families currently in use by RmlUi.
-    @author Peter Curry
- */
-
-class RMLUICORE_API FontProvider : public Rml::Core::FontProvider
-{
-public:
-    static bool Initialise();
-    static void Shutdown();
-
-    /// Adds a new font face to the database. The face's family, style and weight will be determined from the face itself.
-    /// @param[in] file_name The file to load the face from.
-    /// @return True if the face was loaded successfully, false otherwise.
-    static bool LoadFontFace(const String& file_name);
-
-private:
-    FontProvider(void);
-    ~FontProvider(void);
-
-    // Adds a loaded face to the appropriate font family.
-    bool AddFace(void* face, const String& family, Style::FontStyle style, Style::FontWeight weight, bool release_stream);
-    // Loads a FreeType face.
-    void* LoadFace(const String& file_name);
-    // Loads a FreeType face from memory.
-    void* LoadFace(const byte* data, int data_length, const String& source, bool local_data);
-
-    static FontProvider* instance;
-};
-
-}
-}
-}
-
-#endif
-
-#endif
-

+ 6 - 1
Source/Core/Context.cpp

@@ -498,8 +498,13 @@ bool Context::ProcessKeyUp(Input::KeyIdentifier key_identifier, int key_modifier
 		return root->DispatchEvent(EventId::Keyup, parameters);
 }
 
+bool Context::ProcessTextInput(char character)
+{
+	return ProcessTextInput(static_cast<Character>(character));
+}
+
 // Sends a single character of text as text input into RmlUi.
-bool Context::ProcessTextInput(word character)
+bool Context::ProcessTextInput(Character character)
 {
 	// Generate the parameters for the key event.
 	Dictionary parameters;

+ 15 - 2
Source/Core/Core.cpp

@@ -30,13 +30,17 @@
 #include "../../Include/RmlUi/Core.h"
 #include "EventSpecification.h"
 #include "FileInterfaceDefault.h"
-#include "FontEngineInterfaceDefault.h"
 #include "PluginRegistry.h"
 #include "StyleSheetFactory.h"
 #include "TemplateCache.h"
 #include "TextureDatabase.h"
 #include "EventSpecification.h"
 
+#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
+#include "FontEngineDefault/FontEngineInterfaceDefault.h"
+#endif
+
+
 namespace Rml {
 namespace Core {
 
@@ -51,7 +55,6 @@ static FontEngineInterface* font_interface = nullptr;
 
 // Default interfaces should be created and destroyed on Initialise and Shutdown, respectively.
 static UniquePtr<FileInterface> default_file_interface;
-
 static UniquePtr<FontEngineInterface> default_font_interface;
 
 static bool initialised = false;
@@ -286,6 +289,16 @@ int GetNumContexts()
 	return (int) contexts.size();
 }
 
+bool LoadFontFace(const String& file_name, bool fallback_face)
+{
+	return font_interface->LoadFontFace(file_name, fallback_face);
+}
+
+bool LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face)
+{
+	return font_interface->LoadFontFace(data, data_size, font_family, style, weight, fallback_face);
+}
+
 // Registers a generic rmlui plugin
 void RegisterPlugin(Plugin* plugin)
 {

+ 1 - 2
Source/Core/Decorator.cpp

@@ -55,8 +55,7 @@ int Decorator::LoadTexture(const String& texture_name, const String& rcss_path)
 	}
 
 	Texture texture;
-	if (!texture.Load(texture_name, rcss_path))
-		return -1;
+	texture.Set(texture_name, rcss_path);
 
 	additional_textures.push_back(texture);
 	return (int)additional_textures.size();

+ 2 - 1
Source/Core/DecoratorTiledInstancer.cpp

@@ -143,8 +143,9 @@ bool DecoratorTiledInstancer::GetTileProperties(DecoratorTiled::Tile* tiles, Tex
 			{
 				texture = previous_texture;
 			}
-			else if (src_property->source && texture.Load(texture_name, src_property->source->path))
+			else if (src_property->source)
 			{
+				texture.Set(texture_name, src_property->source->path);
 				previous_texture_name = texture_name;
 				previous_texture = texture;
 			}

+ 0 - 1
Source/Core/Element.cpp

@@ -45,7 +45,6 @@
 #include "EventDispatcher.h"
 #include "EventSpecification.h"
 #include "ElementDecoration.h"
-#include "FontFaceHandleDefault.h"
 #include "LayoutEngine.h"
 #include "PluginRegistry.h"
 #include "PropertiesIterator.h"

+ 1 - 1
Source/Core/ElementDocument.cpp

@@ -328,7 +328,7 @@ ElementPtr ElementDocument::CreateTextNode(const String& text)
 	}
 	
 	// Set the text
-	element_text->SetText(StringUtilities::ToUCS2(text));
+	element_text->SetText(text);
 
 	return element;
 }

+ 1 - 5
Source/Core/ElementImage.cpp

@@ -232,11 +232,7 @@ bool ElementImage::LoadTexture()
 	Rml::Core::ElementDocument* document = GetOwnerDocument();
 	URL source_url(document == nullptr ? "" : document->GetSourceURL());
 
-	if (!texture.Load(image_source, source_url.GetPath()))
-	{
-		geometry.SetTexture(nullptr);
-		return false;
-	}
+	texture.Set(image_source, source_url.GetPath());
 
 	// Set the texture onto our geometry object.
 	geometry.SetTexture(&texture);

+ 4 - 7
Source/Core/ElementStyle.cpp

@@ -43,7 +43,6 @@
 #include "ElementBorder.h"
 #include "ElementDecoration.h"
 #include "ElementDefinition.h"
-#include "FontFaceHandleDefault.h"
 #include "ComputeProperty.h"
 #include "PropertiesIterator.h"
 
@@ -575,7 +574,6 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 		values.opacity = parent_values->opacity;
 
 		values.font_family = parent_values->font_family;
-		values.font_charset = parent_values->font_charset;
 		values.font_style = parent_values->font_style;
 		values.font_weight = parent_values->font_weight;
 		values.font_face_handle = parent_values->font_face_handle;
@@ -747,10 +745,6 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 			values.font_family = StringUtilities::ToLower(p->Get<String>());
 			values.font_face_handle = 0;
 			break;
-		case PropertyId::FontCharset:
-			values.font_charset = p->Get<String>();
-			values.font_face_handle = 0;
-			break;
 		case PropertyId::FontStyle:
 			values.font_style = (FontStyle)p->Get< int >();
 			values.font_face_handle = 0;
@@ -873,7 +867,10 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 
 	// The font-face handle is nulled when local font properties are set. In that case we need to retrieve a new handle.
 	if (!values.font_face_handle)
-		values.font_face_handle = ElementUtilities::GetFontFaceHandle(values);
+	{
+		RMLUI_ZoneScopedN("FontFaceHandle");
+		values.font_face_handle = GetFontEngineInterface()->GetFontFaceHandle(values.font_family, values.font_style, values.font_weight, (int)values.font_size);
+	}
 
 	// Next, pass inheritable dirty properties onto our children
 	PropertyIdSet dirty_inherited_properties = (dirty_properties & StyleSheetSpecification::GetRegisteredInheritedProperties());

+ 54 - 50
Source/Core/ElementTextDefault.cpp

@@ -30,7 +30,6 @@
 #include "ElementTextDefault.h"
 #include "ElementDefinition.h"
 #include "ElementStyle.h"
-#include "FontFaceHandleDefault.h"
 #include "../../Include/RmlUi/Core/ElementDocument.h"
 #include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../Include/RmlUi/Core/Event.h"
@@ -39,8 +38,8 @@
 namespace Rml {
 namespace Core {
 
-static bool BuildToken(WString& token, const word*& token_begin, const word* string_end, bool first_token, bool collapse_white_space, bool break_at_endline, Style::TextTransform text_transformation);
-static bool LastToken(const word* token_begin, const word* string_end, bool collapse_white_space, bool break_at_endline);
+static bool BuildToken(String& token, const char*& token_begin, const char* string_end, bool first_token, bool collapse_white_space, bool break_at_endline, Style::TextTransform text_transformation);
+static bool LastToken(const char* token_begin, const char* string_end, bool collapse_white_space, bool break_at_endline);
 
 ElementTextDefault::ElementTextDefault(const String& tag) : ElementText(tag), colour(255, 255, 255), decoration(this)
 {
@@ -51,15 +50,16 @@ ElementTextDefault::ElementTextDefault(const String& tag) : ElementText(tag), co
 
 	geometry_dirty = true;
 
-	font_configuration = -1;
-	font_dirty = true;
+	font_effects_handle = 0;
+	font_effects_dirty = true;
+	font_handle_version = 0;
 }
 
 ElementTextDefault::~ElementTextDefault()
 {
 }
 
-void ElementTextDefault::SetText(const WString& _text)
+void ElementTextDefault::SetText(const String& _text)
 {
 	if (text != _text)
 	{
@@ -70,7 +70,7 @@ void ElementTextDefault::SetText(const WString& _text)
 	}
 }
 
-const WString& ElementTextDefault::GetText() const
+const String& ElementTextDefault::GetText() const
 {
 	return text;
 }
@@ -83,12 +83,15 @@ void ElementTextDefault::OnRender()
 	if (font_face_handle == 0)
 		return;
 	
-	
-	// If our font configuration has potentially changed, update it and force a geometry
-	// generation if necessary.
-	if (font_dirty &&
-		UpdateFontConfiguration())
+	// If our font effects have potentially changed, update it and force a geometry generation if necessary.
+	if (font_effects_dirty && UpdateFontEffects())
+		geometry_dirty = true;
+
+	// Dirty geometry if font version has changed.
+	int new_version = GetFontEngineInterface()->GetVersion(font_face_handle);
+	if (new_version != font_handle_version)
 	{
+		font_handle_version = new_version;
 		geometry_dirty = true;
 	}
 
@@ -164,17 +167,17 @@ bool ElementTextDefault::GenerateToken(float& token_width, int line_begin)
 							white_space_property == WhiteSpace::Prewrap ||
 							white_space_property == WhiteSpace::Preline;
 
-	const word* token_begin = text.c_str() + line_begin;
-	WString token;
+	const char* token_begin = text.c_str() + line_begin;
+	String token;
 
 	BuildToken(token, token_begin, text.c_str() + text.size(), true, collapse_white_space, break_at_endline, computed.text_transform);
-	token_width = (float) GetFontEngineInterface()->GetStringWidth(font_face_handle, token, 0);
+	token_width = (float) GetFontEngineInterface()->GetStringWidth(font_face_handle, token);
 
 	return LastToken(token_begin, text.c_str() + text.size(), collapse_white_space, break_at_endline);
 }
 
 // Generates a line of text rendered from this element
-bool ElementTextDefault::GenerateLine(WString& line, int& line_length, float& line_width, int line_begin, float maximum_line_width, float right_spacing_width, bool trim_whitespace_prefix)
+bool ElementTextDefault::GenerateLine(String& line, int& line_length, float& line_width, int line_begin, float maximum_line_width, float right_spacing_width, bool trim_whitespace_prefix)
 {
 	RMLUI_ZoneScoped;
 
@@ -210,17 +213,19 @@ bool ElementTextDefault::GenerateLine(WString& line, int& line_length, float& li
 	// Starting at the line_begin character, we generate sections of the text (we'll call them tokens) depending on the
 	// white-space parsing parameters. Each section is then appended to the line if it can fit. If not, or if an
 	// endline is found (and we're processing them), then the line is ended. kthxbai!
-
-	const word* token_begin = text.c_str() + line_begin;
-	const word* string_end = text.c_str() + text.size();
+	const char* token_begin = text.c_str() + line_begin;
+	const char* string_end = text.c_str() + text.size();
 	while (token_begin != string_end)
 	{
-		WString token;
-		const word* next_token_begin = token_begin;
+		String token;
+		const char* next_token_begin = token_begin;
+		Character previous_codepoint = Character::Null;
+		if (!line.empty())
+			previous_codepoint = StringUtilities::ToCharacter(StringUtilities::SeekBackwardUTF8(&line.back(), line.data()));
 
 		// Generate the next token and determine its pixel-length.
 		bool break_line = BuildToken(token, next_token_begin, string_end, line.empty() && trim_whitespace_prefix, collapse_white_space, break_at_endline, text_transform_property);
-		int token_width = GetFontEngineInterface()->GetStringWidth(font_face_handle, token, line.empty() ? 0 : line[line.size() - 1]);
+		int token_width = GetFontEngineInterface()->GetStringWidth(font_face_handle, token, previous_codepoint);
 
 		// If we're breaking to fit a line box, check if the token can fit on the line before we add it.
 		if (break_at_line)
@@ -262,15 +267,15 @@ void ElementTextDefault::ClearLines()
 }
 
 // Adds a new line into the text element.
-void ElementTextDefault::AddLine(const Vector2f& line_position, const WString& line)
+void ElementTextDefault::AddLine(const Vector2f& line_position, const String& line)
 {
 	FontFaceHandle font_face_handle = GetFontFaceHandle();
 
 	if (font_face_handle == 0)
 		return;
 
-	if (font_dirty)
-		UpdateFontConfiguration();
+	if (font_effects_dirty)
+		UpdateFontEffects();
 
 	Vector2f baseline_position = line_position + Vector2f(0.0f, (float)GetFontEngineInterface()->GetLineHeight(font_face_handle) - GetFontEngineInterface()->GetBaseline(font_face_handle));
 	lines.push_back(Line(line, baseline_position));
@@ -307,7 +312,6 @@ void ElementTextDefault::OnPropertyChange(const PropertyIdSet& changed_propertie
 	}
 
 	if (changed_properties.Contains(PropertyId::FontFamily) ||
-		changed_properties.Contains(PropertyId::FontCharset) ||
 		changed_properties.Contains(PropertyId::FontWeight) ||
 		changed_properties.Contains(PropertyId::FontStyle) ||
 		changed_properties.Contains(PropertyId::FontSize))
@@ -315,7 +319,7 @@ void ElementTextDefault::OnPropertyChange(const PropertyIdSet& changed_propertie
 		font_face_changed = true;
 
 		geometry.clear();
-		font_dirty = true;
+		font_effects_dirty = true;
 	}
 
 	if (changed_properties.Contains(PropertyId::TextDecoration))
@@ -331,7 +335,7 @@ void ElementTextDefault::OnPropertyChange(const PropertyIdSet& changed_propertie
 				if (font_face_handle != 0)
 				{
 					for (size_t i = 0; i < lines.size(); ++i)
-						GenerateDecoration(font_face_handle, lines[i]);
+						GenerateLineDecoration(font_face_handle, lines[i]);
 				}
 
 				generated_decoration = decoration_property;
@@ -362,18 +366,18 @@ void ElementTextDefault::OnPropertyChange(const PropertyIdSet& changed_propertie
 // Returns the RML of this element
 void ElementTextDefault::GetRML(String& content)
 {
-	content += StringUtilities::ToUTF8(text);
+	content += text;
 }
 
 // Updates the configuration this element uses for its font.
-bool ElementTextDefault::UpdateFontConfiguration()
+bool ElementTextDefault::UpdateFontEffects()
 {
 	RMLUI_ZoneScoped;
 
 	if (GetFontFaceHandle() == 0)
 		return false;
 
-	font_dirty = false;
+	font_effects_dirty = false;
 
 	static const FontEffectList empty_font_effects;
 
@@ -384,10 +388,10 @@ bool ElementTextDefault::UpdateFontConfiguration()
 
 	// Request a font layer configuration to match this set of effects. If this is different from
 	// our old configuration, then return true to indicate we'll need to regenerate geometry.
-	int new_configuration = GetFontEngineInterface()->GenerateLayerConfiguration(GetFontFaceHandle(), *font_effects);
-	if (new_configuration != font_configuration)
+	FontEffectsHandle new_font_effects_handle = GetFontEngineInterface()->PrepareFontEffects(GetFontFaceHandle(), *font_effects);
+	if (new_font_effects_handle != font_effects_handle)
 	{
-		font_configuration = new_configuration;
+		font_effects_handle = new_font_effects_handle;
 		return true;
 	}
 
@@ -412,23 +416,23 @@ void ElementTextDefault::GenerateGeometry(const FontFaceHandle font_face_handle)
 
 void ElementTextDefault::GenerateGeometry(const FontFaceHandle font_face_handle, Line& line)
 {
-	line.width = GetFontEngineInterface()->GenerateString(font_face_handle, geometry, line.text, line.position, colour, font_configuration);
+	line.width = GetFontEngineInterface()->GenerateString(font_face_handle, font_effects_handle, line.text, line.position, colour, geometry);
 	for (size_t i = 0; i < geometry.size(); ++i)
 		geometry[i].SetHostElement(this);
 
 	if (decoration_property != Style::TextDecoration::None)
-		GenerateDecoration(font_face_handle, line);
+		GenerateLineDecoration(font_face_handle, line);
 }
 
 // Generates any geometry necessary for rendering a line decoration (underline, strike-through, etc).
-void ElementTextDefault::GenerateDecoration(const FontFaceHandle font_face_handle, const Line& line)
+void ElementTextDefault::GenerateLineDecoration(const FontFaceHandle font_face_handle, const Line& line)
 {
 	RMLUI_ZoneScopedC(0xA52A2A);
 	
 	GeometryUtilities::GenerateLine(font_face_handle, &decoration, line.position, line.width, decoration_property, colour);
 }
 
-static bool BuildToken(WString& token, const word*& token_begin, const word* string_end, bool first_token, bool collapse_white_space, bool break_at_endline, Style::TextTransform text_transformation)
+static bool BuildToken(String& token, const char*& token_begin, const char* string_end, bool first_token, bool collapse_white_space, bool break_at_endline, Style::TextTransform text_transformation)
 {
 	RMLUI_ASSERT(token_begin != string_end);
 
@@ -445,9 +449,9 @@ static bool BuildToken(WString& token, const word*& token_begin, const word* str
 	while (token_begin != string_end)
 	{
 		bool force_non_whitespace = false;
-		word character = *token_begin;
+		char character = *token_begin;
 
-		const word* escape_begin = token_begin;
+		const char* escape_begin = token_begin;
 
 		// Check for an ampersand; if we find one, we've got an HTML escaped character.
 		if (character == '&')
@@ -467,17 +471,17 @@ static bool BuildToken(WString& token, const word*& token_begin, const word* str
 			// is not recognised, print the token like normal text.
 			else
 			{
-				WString ucs2_escape_code(escape_begin + 1, token_begin);
+				String escape_code(escape_begin + 1, token_begin);
 
-				if (ucs2_escape_code == L"lt")
+				if (escape_code == "lt")
 					character = '<';
-				else if (ucs2_escape_code == L"gt")
+				else if (escape_code == "gt")
 					character = '>';
-				else if (ucs2_escape_code == L"amp")
+				else if (escape_code == "amp")
 					character = '&';
-				else if (ucs2_escape_code == L"quot")
+				else if (escape_code == "quot")
 					character = '"';
-				else if (ucs2_escape_code == L"nbsp")
+				else if (escape_code == "nbsp")
 				{
 					character = ' ';
 					force_non_whitespace = true;
@@ -543,12 +547,12 @@ static bool BuildToken(WString& token, const word*& token_begin, const word* str
 			if (text_transformation == Style::TextTransform::Uppercase)
 			{
 				if (character >= 'a' && character <= 'z')
-					character += (Rml::Core::word)('A' - 'a');
+					character += ('A' - 'a');
 			}
 			else if (text_transformation == Style::TextTransform::Lowercase)
 			{
 				if (character >= 'A' && character <= 'Z')
-					character -= (Rml::Core::word)('A' - 'a');
+					character -= ('A' - 'a');
 			}
 
 			token += character;
@@ -560,14 +564,14 @@ static bool BuildToken(WString& token, const word*& token_begin, const word* str
 	return false;
 }
 
-static bool LastToken(const word* token_begin, const word* string_end, bool collapse_white_space, bool break_at_endline)
+static bool LastToken(const char* token_begin, const char* string_end, bool collapse_white_space, bool break_at_endline)
 {
 	bool last_token = (token_begin == string_end);
 	if (collapse_white_space &&
 		!last_token)
 	{
 		last_token = true;
-		const word* character = token_begin;
+		const char* character = token_begin;
 
 		while (character != string_end)
 		{

+ 14 - 17
Source/Core/ElementTextDefault.h

@@ -46,8 +46,8 @@ public:
 	ElementTextDefault(const String& tag);
 	virtual ~ElementTextDefault();
 
-	void SetText(const WString& text) override;
-	const WString& GetText() const override;
+	void SetText(const String& text) override;
+	const String& GetText() const override;
 
 	void OnRender() override;
 
@@ -65,14 +65,14 @@ public:
 	/// @param[in] right_spacing_width The width (in pixels) of the spacing (consisting of margins, padding, etc) that must be remaining on the right of the line if the last of the text is rendered onto this line.
 	/// @param[in] trim_whitespace_prefix If we're collapsing whitespace, whether or remove all prefixing whitespace or collapse it down to a single space.
 	/// @return True if the line reached the end of the element's text, false if not.
-	bool GenerateLine(WString& line, int& line_length, float& line_width, int line_begin, float maximum_line_width, float right_spacing_width, bool trim_whitespace_prefix) override;
+	bool GenerateLine(String& line, int& line_length, float& line_width, int line_begin, float maximum_line_width, float right_spacing_width, bool trim_whitespace_prefix) override;
 
 	/// Clears all lines of generated text and prepares the element for generating new lines.
 	void ClearLines() override;
 	/// Adds a new line into the text element.
 	/// @param[in] line_position The position of this line, as an offset from the first line.
 	/// @param[in] line The contents of the line..
-	void AddLine(const Vector2f& line_position, const WString& line) override;
+	void AddLine(const Vector2f& line_position, const String& line) override;
 
 	/// Prevents the element from dirtying its document's layout when its text is changed.
 	void SuppressAutoLayout() override;
@@ -85,19 +85,14 @@ protected:
 	void GetRML(String& content) override;
 
 private:
-	// Updates the configuration this element uses for its font, depending on which font effects
-	// are active.
-	bool UpdateFontConfiguration();
+	// Prepares the font effects this element uses for its font.
+	bool UpdateFontEffects();
 
 	// Used to store the position and length of each line we have geometry for.
 	struct Line
 	{
-		Line(const WString& text, const Vector2f& position) : text(text), position(position)
-		{
-			width = 0;
-		}
-
-		WString text;
+		Line(const String& text, const Vector2f& position) : text(text), position(position), width(0) {}
+		String text;
 		Vector2f position;
 		int width;
 	};
@@ -107,9 +102,9 @@ private:
 	// Generates the geometry for a single line of text.
 	void GenerateGeometry(const FontFaceHandle font_face_handle, Line& line);
 	// Generates any geometry necessary for rendering a line decoration (underline, strike-through, etc).
-	void GenerateDecoration(const FontFaceHandle font_face_handle, const Line& line);
+	void GenerateLineDecoration(const FontFaceHandle font_face_handle, const Line& line);
 
-	WString text;
+	String text;
 
 	typedef std::vector< Line > LineList;
 	LineList lines;
@@ -130,8 +125,10 @@ private:
 	// it isn't being changed.
 	Style::TextDecoration decoration_property;
 
-	int font_configuration;
-	bool font_dirty;
+	FontEffectsHandle font_effects_handle;
+	bool font_effects_dirty;
+
+	int font_handle_version;
 };
 
 }

+ 1 - 15
Source/Core/ElementUtilities.cpp

@@ -32,7 +32,6 @@
 #include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include <queue>
 #include <limits>
-#include "FontFaceHandleDefault.h"
 #include "LayoutEngine.h"
 #include "ElementStyle.h"
 
@@ -138,19 +137,6 @@ void ElementUtilities::GetElementsByClassName(ElementList& elements, Element* ro
 	}
 }
 
-// Returns the element's font face.
-FontFaceHandle ElementUtilities::GetFontFaceHandle(const Style::ComputedValues& computed_values)
-{
-	RMLUI_ZoneScoped;
-
-	static const String default_charset = "U+0020-007E";
-
-	const String& charset = (computed_values.font_charset.empty() ? default_charset : computed_values.font_charset);
-	int font_size = (int)computed_values.font_size;
-
-	return GetFontEngineInterface()->GetFontFaceHandle(computed_values.font_family, charset, computed_values.font_style, computed_values.font_weight, font_size);
-}
-
 float ElementUtilities::GetDensityIndependentPixelRatio(Element * element)
 {
 	Context* context = element->GetContext();
@@ -161,7 +147,7 @@ float ElementUtilities::GetDensityIndependentPixelRatio(Element * element)
 }
 
 // Returns the width of a string rendered within the context of the given element.
-int ElementUtilities::GetStringWidth(Element* element, const WString& string)
+int ElementUtilities::GetStringWidth(Element* element, const String& string)
 {
 	FontFaceHandle font_face_handle = element->GetFontFaceHandle();
 	if (font_face_handle == 0)

+ 1 - 1
Source/Core/Factory.cpp

@@ -296,7 +296,7 @@ bool Factory::InstanceElementText(Element* parent, const String& text)
 			return false;
 		}
 
-		text_element->SetText(StringUtilities::ToUCS2(translated_data));
+		text_element->SetText(translated_data);
 
 		// Add to active node.
 		parent->AppendChild(std::move(element));

+ 0 - 149
Source/Core/FontDatabaseDefault.cpp

@@ -1,149 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include "precompiled.h"
-#include <RmlUi/Core.h>
-#include "FontFamily.h"
-#include "FreeType/FontProvider.h"
-#include "BitmapFont/FontProvider.h"
-#include "FontDatabaseDefault.h"
-
-namespace Rml {
-namespace Core {
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-FontDatabaseDefault* FontDatabaseDefault::instance = nullptr;
-FontDatabaseDefault::FontProviderTable FontDatabaseDefault::font_provider_table;
-
-FontDatabaseDefault::FontDatabaseDefault()
-{
-	RMLUI_ASSERT(instance == nullptr);
-	instance = this;
-}
-
-FontDatabaseDefault::~FontDatabaseDefault()
-{
-	RMLUI_ASSERT(instance == this);
-	instance = nullptr;
-}
-
-bool FontDatabaseDefault::Initialise()
-{
-	if (instance == nullptr)
-	{
-		new FontDatabaseDefault();
-
-        if(!FreeType::FontProvider::Initialise())
-            return false;
-
-        if(!BitmapFont::FontProvider::Initialise())
-            return false;
-	}
-
-	return true;
-}
-
-void FontDatabaseDefault::Shutdown()
-{
-	if (instance != nullptr)
-	{
-        FreeType::FontProvider::Shutdown();
-        BitmapFont::FontProvider::Shutdown();
-
-		delete instance;
-	}
-}
-
-// Loads a new font face.
-bool FontDatabaseDefault::LoadFontFace(const String& file_name)
-{
-    FontProviderType font_provider_type = GetFontProviderType(file_name);
-
-    switch(font_provider_type)
-    {
-        case FreeType:
-            return FreeType::FontProvider::LoadFontFace(file_name);
-
-        case BitmapFont:
-            return BitmapFont::FontProvider::LoadFontFace(file_name);
-
-        default:
-            return false;
-    }
-}
-
-FontDatabaseDefault::FontProviderType FontDatabaseDefault::GetFontProviderType(const String& file_name)
-{
-    if(file_name.find(".fnt") != String::npos)
-    {
-        return BitmapFont;
-    }
-    else
-    {
-        return FreeType;
-    }
-}
-
-// Returns a handle to a font face that can be used to position and render text.
-SharedPtr<FontFaceHandleDefault> FontDatabaseDefault::GetFontFaceHandle(const String& family, const String& charset, Style::FontStyle style, Style::FontWeight weight, int size)
-{
-    size_t provider_count = font_provider_table.size();
-
-    for(size_t provider_index = 0; provider_index < provider_count; ++provider_index)
-    {
-		SharedPtr<FontFaceHandleDefault> face_handle = font_provider_table[ provider_index ]->GetFontFaceHandle(family, charset, style, weight, size);
-
-        if(face_handle)
-            return face_handle;
-    }
-
-    return nullptr;
-}
-
-void FontDatabaseDefault::AddFontProvider(FontProvider * provider)
-{
-    instance->font_provider_table.push_back(provider);
-}
-
-void FontDatabaseDefault::RemoveFontProvider(FontProvider * provider)
-{
-    for(FontProviderTable::iterator i = instance->font_provider_table.begin(); i != instance->font_provider_table.end(); ++i)
-    {
-        if(*i == provider)
-        {
-            instance->font_provider_table.erase(i);
-            return;
-        }
-    }
-}
-
-#endif
-
-}
-}

+ 28 - 28
Source/Core/FontEngineInterfaceDefault.cpp → Source/Core/FontEngineDefault/FontEngineInterfaceDefault.cpp

@@ -27,93 +27,93 @@
  */
 
 #include "precompiled.h"
-#include "FontDatabaseDefault.h"
+#include "FontProvider.h"
 #include "FontFaceHandleDefault.h"
 #include "FontEngineInterfaceDefault.h"
 
 namespace Rml {
 namespace Core {
 
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
 FontEngineInterfaceDefault::FontEngineInterfaceDefault()
 {
-	FontDatabaseDefault::Initialise();
+	FontProvider::Initialise();
 }
 
 FontEngineInterfaceDefault::~FontEngineInterfaceDefault()
 {
-	FontDatabaseDefault::Shutdown();
+	FontProvider::Shutdown();
 }
 
-bool FontEngineInterfaceDefault::LoadFontFace(const String& file_name)
+bool FontEngineInterfaceDefault::LoadFontFace(const String& file_name, bool fallback_face)
 {
-	return FontDatabaseDefault::LoadFontFace(file_name);
+	return FontProvider::LoadFontFace(file_name, fallback_face);
 }
 
-FontFaceHandle FontEngineInterfaceDefault::GetFontFaceHandle(const String& family,
-	const String& charset, Style::FontStyle style, Style::FontWeight weight, int size)
+bool FontEngineInterfaceDefault::LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face)
 {
-	auto handle = FontDatabaseDefault::GetFontFaceHandle(family, charset, style, weight, size);
-	return reinterpret_cast<FontFaceHandle>(handle.get());
+	return FontProvider::LoadFontFace(data, data_size, font_family, style, weight, fallback_face);
 }
-	
-int FontEngineInterfaceDefault::GenerateLayerConfiguration(FontFaceHandle handle, const FontEffectList& font_effects) const
+
+FontFaceHandle FontEngineInterfaceDefault::GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size)
 {
-	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
-	return handle_default->GenerateLayerConfiguration(font_effects);
+	auto handle = FontProvider::GetFontFaceHandle(family, style, weight, size);
+	return reinterpret_cast<FontFaceHandle>(handle);
 }
-
-int FontEngineInterfaceDefault::GetCharacterWidth(FontFaceHandle handle) const
+	
+FontEffectsHandle FontEngineInterfaceDefault::PrepareFontEffects(FontFaceHandle handle, const FontEffectList& font_effects)
 {
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
-	return handle_default->GetCharacterWidth();
+	return (FontEffectsHandle)handle_default->GenerateLayerConfiguration(font_effects);
 }
 
-int FontEngineInterfaceDefault::GetSize(FontFaceHandle handle) const
+int FontEngineInterfaceDefault::GetSize(FontFaceHandle handle)
 {
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
 	return handle_default->GetSize();
 }
 
-int FontEngineInterfaceDefault::GetXHeight(FontFaceHandle handle) const
+int FontEngineInterfaceDefault::GetXHeight(FontFaceHandle handle)
 {
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
 	return handle_default->GetXHeight();
 }
 
-int FontEngineInterfaceDefault::GetLineHeight(FontFaceHandle handle) const
+int FontEngineInterfaceDefault::GetLineHeight(FontFaceHandle handle)
 {
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
 	return handle_default->GetLineHeight();
 }
 
-int FontEngineInterfaceDefault::GetBaseline(FontFaceHandle handle) const
+int FontEngineInterfaceDefault::GetBaseline(FontFaceHandle handle)
 {
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
 	return handle_default->GetBaseline();
 }
 
-float FontEngineInterfaceDefault::GetUnderline(FontFaceHandle handle, float *thickness) const
+float FontEngineInterfaceDefault::GetUnderline(FontFaceHandle handle, float& thickness)
 {
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
 	return handle_default->GetUnderline(thickness);
 }
 
-int FontEngineInterfaceDefault::GetStringWidth(FontFaceHandle handle, const WString& string, word prior_character)
+int FontEngineInterfaceDefault::GetStringWidth(FontFaceHandle handle, const String& string, Character prior_character)
 {
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
 	return handle_default->GetStringWidth(string, prior_character);
 }
 
-int FontEngineInterfaceDefault::GenerateString(FontFaceHandle handle, GeometryList& geometry, const WString& string,
-	const Vector2f& position, const Colourb& colour, int layer_configuration) const
+int FontEngineInterfaceDefault::GenerateString(FontFaceHandle handle, FontEffectsHandle font_effects_handle, const String& string,
+	const Vector2f& position, const Colourb& colour, GeometryList& geometry)
 {
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
-	return handle_default->GenerateString(geometry, string, position, colour, layer_configuration);
+	return handle_default->GenerateString(geometry, string, position, colour, (int)font_effects_handle);
 }
 
-#endif
+int FontEngineInterfaceDefault::GetVersion(FontFaceHandle handle)
+{
+	auto handle_default = reinterpret_cast<FontFaceHandleDefault*>(handle);
+	return handle_default->GetVersion();
+}
 
 }
 }

+ 82 - 0
Source/Core/FontEngineDefault/FontEngineInterfaceDefault.h

@@ -0,0 +1,82 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef RMLUICOREFONTENGINEINTERFACEDEFAULT_H
+#define RMLUICOREFONTENGINEINTERFACEDEFAULT_H
+
+#include "../../../Include/RmlUi/Core/FontEngineInterface.h"
+
+namespace Rml {
+namespace Core {
+
+class RMLUICORE_API FontEngineInterfaceDefault : public FontEngineInterface
+{
+public:
+	FontEngineInterfaceDefault();
+	virtual ~FontEngineInterfaceDefault();
+
+	/// Adds a new font face to the database. The face's family, style and weight will be determined from the face itself.
+	bool LoadFontFace(const String& file_name, bool fallback_face) override;
+
+	/// Adds a new font face to the database using the provided family, style and weight.
+	bool LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face) override;
+
+	/// Returns a handle to a font face that can be used to position and render text. This will return the closest match
+	/// it can find, but in the event a font family is requested that does not exist, NULL will be returned instead of a
+	/// valid handle.
+	FontFaceHandle GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size) override;
+
+	/// Prepares for font effects by configuring a new, or returning an existing, layer configuration.
+	FontEffectsHandle PrepareFontEffects(FontFaceHandle, const FontEffectList& font_effects) override;
+
+	/// Returns the point size of this font face.
+	int GetSize(FontFaceHandle) override;
+	/// Returns the pixel height of a lower-case x in this font face.
+	int GetXHeight(FontFaceHandle) override;
+	/// Returns the default height between this font face's baselines.
+	int GetLineHeight(FontFaceHandle) override;
+
+	/// Returns the font's baseline, as a pixel offset from the bottom of the font.
+	int GetBaseline(FontFaceHandle) override;
+
+	/// Returns the font's underline, as a pixel offset from the bottom of the font.
+	float GetUnderline(FontFaceHandle, float& thickness) override;
+
+	/// Returns the width a string will take up if rendered with this handle.
+	int GetStringWidth(FontFaceHandle, const String& string, Character prior_character) override;
+
+	/// Generates the geometry required to render a single line of text.
+	int GenerateString(FontFaceHandle, FontEffectsHandle, const String& string, const Vector2f& position, const Colourb& colour, GeometryList& geometry) override;
+
+	/// Returns the current version of the font face.
+	int GetVersion(FontFaceHandle handle) override;
+};
+
+}
+}
+
+#endif

+ 39 - 3
Source/Core/FontFace.cpp → Source/Core/FontEngineDefault/FontFace.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -27,23 +27,30 @@
  */
 
 #include "precompiled.h"
+#include "../../../Include/RmlUi/Core/Log.h"
 #include "FontFace.h"
 #include "FontFaceHandleDefault.h"
-#include "../../Include/RmlUi/Core/Log.h"
+#include "FreeTypeInterface.h"
 
 namespace Rml {
 namespace Core {
 
-FontFace::FontFace(Style::FontStyle _style, Style::FontWeight _weight, bool _release_stream)
+FontFace::FontFace(FontFaceHandleFreetype _face, Style::FontStyle _style, Style::FontWeight _weight, bool _release_stream)
 {
 	style = _style;
 	weight = _weight;
+	face = _face;
 
 	release_stream = _release_stream;
 }
 
 FontFace::~FontFace()
 {
+	if (face) 
+	{
+		FreeType::ReleaseFace(face, release_stream);
+		face = 0;
+	}
 	handles.clear();
 }
 
@@ -59,5 +66,34 @@ Style::FontWeight FontFace::GetWeight() const
 	return weight;
 }
 
+FontFaceHandleDefault* FontFace::GetHandle(int size) {
+	auto it = handles.find(size);
+	if (it != handles.end())
+		return it->second.get();
+
+	// See if this face has been released.
+	if (!face)
+	{
+		Log::Message(Log::LT_WARNING, "Font face has been released, unable to generate new handle.");
+		return nullptr;
+	}
+
+	// Construct and initialise the new handle.
+	auto handle = std::make_unique<FontFaceHandleDefault>();
+	if (!handle->Initialize(face, size))
+	{
+		handles[size] = nullptr;
+		return nullptr;
+	}
+
+	FontFaceHandleDefault* result = handle.get();
+
+	// Save the new handle to the font face
+	handles[size] = std::move(handle);
+
+	return result;
+}
+
+
 }
 }

+ 12 - 18
Source/Core/FontFace.h → Source/Core/FontEngineDefault/FontFace.h

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -29,7 +29,8 @@
 #ifndef RMLUICOREFONTFACE_H
 #define RMLUICOREFONTFACE_H
 
-#include <RmlUi/Core/ComputedValues.h>
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
+#include "FontTypes.h"
 
 namespace Rml {
 namespace Core {
@@ -43,35 +44,28 @@ class FontFaceHandleDefault;
 class FontFace
 {
 public:
-    FontFace(Style::FontStyle style, Style::FontWeight weight, bool release_stream);
-    virtual ~FontFace();
+	FontFace(FontFaceHandleFreetype face, Style::FontStyle style, Style::FontWeight weight, bool release_stream);
+	~FontFace();
 
-	/// Returns the style of the font face.
-	/// @return The font face's style.
 	Style::FontStyle GetStyle() const;
-	/// Returns the weight of the font face.
-	/// @return The font face's weight.
 	Style::FontWeight GetWeight() const;
 
 	/// Returns a handle for positioning and rendering this face at the given size.
-	/// @param[in] charset The set of characters in the handle, as a comma-separated list of unicode ranges.
 	/// @param[in] size The size of the desired handle, in points.
-	/// @return The shared font handle.
-    virtual SharedPtr<FontFaceHandleDefault> GetHandle(const String& charset, int size) = 0;
-
-	/// Releases the face's FreeType face structure. This will mean handles for new sizes cannot be constructed,
-	/// but existing ones can still be fetched.
-    virtual void ReleaseFace() = 0;
+	/// @return The font handle.
+	FontFaceHandleDefault* GetHandle(int size);
 
-protected:
+private:
 	Style::FontStyle style;
 	Style::FontWeight weight;
 
 	bool release_stream;
 
-	typedef std::vector< SharedPtr<FontFaceHandleDefault> > HandleList;
-	typedef UnorderedMap< int, HandleList > HandleMap;
+	// Key is font size
+	using HandleMap = UnorderedMap< int, UniquePtr<FontFaceHandleDefault> >;
 	HandleMap handles;
+
+	FontFaceHandleFreetype face;
 };
 
 }

+ 185 - 79
Source/Core/FontFaceHandleDefault.cpp → Source/Core/FontEngineDefault/FontFaceHandleDefault.cpp

@@ -27,104 +27,101 @@
  */
 
 #include "precompiled.h"
+#include "../TextureLayout.h"
 #include "FontFaceHandleDefault.h"
-#include <algorithm>
-#include "../../Include/RmlUi/Core.h"
+#include "FontProvider.h"
 #include "FontFaceLayer.h"
-#include "TextureLayout.h"
+#include "FreeTypeInterface.h"
 
 namespace Rml {
 namespace Core {
 
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-	
 FontFaceHandleDefault::FontFaceHandleDefault()
 {
-	size = 0;
-	average_advance = 0;
-	x_height = 0;
-	line_height = 0;
-	baseline = 0;
-
-	underline_position = 0;
-	underline_thickness = 0;
-
 	base_layer = nullptr;
+	metrics = {};
+	ft_face = 0;
 }
 
 FontFaceHandleDefault::~FontFaceHandleDefault()
 {
-	for (FontGlyphList::iterator i = glyphs.begin(); i != glyphs.end(); ++i)
-		delete[] i->bitmap_data;
-
-	for (FontLayerMap::iterator i = layers.begin(); i != layers.end(); ++i)
-		delete i->second;
+	glyphs.clear();
+	layers.clear();
 }
 
-// Returns the point size of this font face.
-int FontFaceHandleDefault::GetSize() const
+bool FontFaceHandleDefault::Initialize(FontFaceHandleFreetype face, int font_size)
 {
-	return size;
+	ft_face = face;
+
+	RMLUI_ASSERTMSG(layer_configurations.empty(), "Initialize must only be called once.");
+
+	if (!FreeType::InitialiseFaceHandle(ft_face, font_size, glyphs, metrics))
+	{
+		return false;
+	}
+
+	// Generate the default layer and layer configuration.
+	base_layer = GetOrCreateLayer(nullptr);
+	layer_configurations.push_back(LayerConfiguration{ base_layer });
+
+	return true;
 }
 
-// Returns the average advance of all glyphs in this font face.
-int FontFaceHandleDefault::GetCharacterWidth() const
+// Returns the point size of this font face.
+int FontFaceHandleDefault::GetSize() const
 {
-	return average_advance;
+	return metrics.size;
 }
 
 // Returns the pixel height of a lower-case x in this font face.
 int FontFaceHandleDefault::GetXHeight() const
 {
-	return x_height;
+	return metrics.x_height;
 }
 
 // Returns the default height between this font face's baselines.
 int FontFaceHandleDefault::GetLineHeight() const
 {
-	return line_height;
+	return metrics.line_height;
 }
 
 // Returns the font's baseline.
 int FontFaceHandleDefault::GetBaseline() const
 {
-	return baseline;
+	return metrics.baseline;
 }
 
 // Returns the font's glyphs.
-const FontGlyphList& FontFaceHandleDefault::GetGlyphs() const
+const FontGlyphMap& FontFaceHandleDefault::GetGlyphs() const
 {
 	return glyphs;
 }
 
-float FontFaceHandleDefault::GetUnderline(float *thickness) const
+float FontFaceHandleDefault::GetUnderline(float& thickness) const
 {
-	if (thickness != nullptr) {
-		*thickness = underline_thickness;
-	}
-	return underline_position;
+	thickness = metrics.underline_thickness;
+	return metrics.underline_position;
 }
 
 // Returns the width a string will take up if rendered with this handle.
-int FontFaceHandleDefault::GetStringWidth(const WString& string, word prior_character) const
+int FontFaceHandleDefault::GetStringWidth(const String& string, Character prior_character)
 {
 	int width = 0;
-
-	for (size_t i = 0; i < string.size(); i++)
+	for (auto it_string = StringIteratorU8(string); it_string; ++it_string)
 	{
-		word character_code = string[i];
+		Character character = *it_string;
 
-		if (character_code >= glyphs.size())
+		const FontGlyph* glyph = GetOrAppendGlyph(character);
+		if (!glyph)
 			continue;
-		const FontGlyph &glyph = glyphs[character_code];
 
 		// Adjust the cursor for the kerning between this character and the previous one.
-		if (prior_character != 0)
-			width += GetKerning(prior_character, string[i]);
+		if (prior_character != Character::Null)
+			width += GetKerning(prior_character, character);
 		// Adjust the cursor for this character's advance.
-		width += glyph.advance;
+		width += glyph->advance;
 
-		prior_character = character_code;
+		prior_character = character;
 	}
 
 	return width;
@@ -183,7 +180,8 @@ int FontFaceHandleDefault::GenerateLayerConfiguration(const FontEffectList& font
 			added_base_layer = true;
 		}
 
-		layer_configuration.push_back(GenerateLayer(font_effects[i]));
+		FontFaceLayer* new_layer = GetOrCreateLayer(font_effects[i]);
+		layer_configuration.push_back(new_layer);
 	}
 
 	// Add the base layer now if we still haven't added it.
@@ -194,17 +192,20 @@ int FontFaceHandleDefault::GenerateLayerConfiguration(const FontEffectList& font
 }
 
 // Generates the texture data for a layer (for the texture database).
-bool FontFaceHandleDefault::GenerateLayerTexture(const byte*& texture_data, Vector2i& texture_dimensions, FontEffect* layer_id, int texture_id)
+bool FontFaceHandleDefault::GenerateLayerTexture(UniquePtr<const byte[]>& texture_data, Vector2i& texture_dimensions, const FontEffect* layer_id, int texture_id, int handle_version) const
 {
-	FontLayerMap::iterator layer_iterator = layers.find(layer_id);
+	if (handle_version != version)
+		return false;
+
+	auto layer_iterator = layers.find(layer_id);
 	if (layer_iterator == layers.end())
 		return false;
 
-	return layer_iterator->second->GenerateTexture(texture_data, texture_dimensions, texture_id);
+	return layer_iterator->second->GenerateTexture(texture_data, texture_dimensions, texture_id, glyphs);
 }
 
 // Generates the geometry required to render a single line of text.
-int FontFaceHandleDefault::GenerateString(GeometryList& geometry, const WString& string, const Vector2f& position, const Colourb& colour, int layer_configuration_index) const
+int FontFaceHandleDefault::GenerateString(GeometryList& geometry, const String& string, const Vector2f& position, const Colourb& colour, int layer_configuration_index)
 {
 	int geometry_index = 0;
 	int line_width = 0;
@@ -212,8 +213,14 @@ int FontFaceHandleDefault::GenerateString(GeometryList& geometry, const WString&
 	RMLUI_ASSERT(layer_configuration_index >= 0);
 	RMLUI_ASSERT(layer_configuration_index < (int) layer_configurations.size());
 
+	UpdateLayersOnDirty();
+
 	// Fetch the requested configuration and generate the geometry for each one.
 	const LayerConfiguration& layer_configuration = layer_configurations[layer_configuration_index];
+
+	// Reserve for the common case of one texture per layer.
+	geometry.reserve(layer_configuration.size());
+
 	for (size_t i = 0; i < layer_configuration.size(); ++i)
 	{
 		FontFaceLayer* layer = layer_configuration[i];
@@ -235,24 +242,26 @@ int FontFaceHandleDefault::GenerateString(GeometryList& geometry, const WString&
 			geometry[geometry_index + i].SetTexture(layer->GetTexture(i));
 
 		line_width = 0;
-		word prior_character = 0;
+		Character prior_character = Character::Null;
 
 		geometry[geometry_index].GetIndices().reserve(string.size() * 6);
 		geometry[geometry_index].GetVertices().reserve(string.size() * 4);
 
-		for (const word character : string)
+		for (auto it_string = StringIteratorU8(string); it_string; ++it_string)
 		{
-			if (character >= glyphs.size())
+			Character character = *it_string;
+
+			const FontGlyph* glyph = GetOrAppendGlyph(character);
+			if (!glyph)
 				continue;
-			const FontGlyph &glyph = glyphs[character];
 
 			// Adjust the cursor for the kerning between this character and the previous one.
-			if (prior_character != 0)
+			if (prior_character != Character::Null)
 				line_width += GetKerning(prior_character, character);
 
 			layer->GenerateGeometry(&geometry[geometry_index], character, Vector2f(position.x + line_width, position.y), layer_colour);
 
-			line_width += glyph.advance;
+			line_width += glyph->advance;
 			prior_character = character;
 		}
 
@@ -265,70 +274,167 @@ int FontFaceHandleDefault::GenerateString(GeometryList& geometry, const WString&
 	return line_width;
 }
 
-// Returns the font face's raw charset (the charset range as a string).
-const String& FontFaceHandleDefault::GetRawCharset() const
+bool FontFaceHandleDefault::UpdateLayersOnDirty()
 {
-	return raw_charset;
+	bool result = false;
+
+	// If we are dirty, regenerate all the layers and increment the version
+	if(is_layers_dirty && base_layer)
+	{
+		is_layers_dirty = false;
+		++version;
+
+		// Regenerate all the layers
+		for (auto& pair : layers)
+		{
+			FontFaceLayer* layer = pair.second.get();
+			GenerateLayer(layer);
+		}
+
+		result = true;
+	}
+
+	return result;
 }
 
-// Returns the font face's charset.
-const UnicodeRangeList& FontFaceHandleDefault::GetCharset() const
+int FontFaceHandleDefault::GetVersion() const 
 {
-	return charset;
+	return version;
 }
 
-Rml::Core::FontFaceLayer* FontFaceHandleDefault::CreateNewLayer()
+bool FontFaceHandleDefault::AppendGlyph(Character character)
 {
-	return new Rml::Core::FontFaceLayer();
+	bool result = FreeType::AppendGlyph(ft_face, metrics.size, character, glyphs);
+	return result;
+}
+
+int FontFaceHandleDefault::GetKerning(Character lhs, Character rhs) const
+{
+	int result = FreeType::GetKerning(ft_face, metrics.size, lhs, rhs);
+	return result;
+}
+
+const FontGlyph* FontFaceHandleDefault::GetOrAppendGlyph(Character& character, bool look_in_fallback_fonts)
+{
+	// Don't try to render control characters
+	if ((char32_t)character < (char32_t)' ')
+		return nullptr;
+
+	auto it_glyph = glyphs.find(character);
+	if (it_glyph == glyphs.end())
+	{
+		bool result = AppendGlyph(character);
+
+		if (result)
+		{
+			it_glyph = glyphs.find(character);
+			if (it_glyph == glyphs.end())
+			{
+				RMLUI_ERROR;
+				return nullptr;
+			}
+
+			is_layers_dirty = true;
+		}
+		else if (look_in_fallback_fonts)
+		{
+			const int num_fallback_faces = FontProvider::CountFallbackFontFaces();
+			for (int i = 0; i < num_fallback_faces; i++)
+			{
+				FontFaceHandleDefault* fallback_face = FontProvider::GetFallbackFontFace(i, metrics.size);
+				if (!fallback_face || fallback_face == this)
+					continue;
+
+				const FontGlyph* glyph = fallback_face->GetOrAppendGlyph(character, false);
+				if (glyph)
+				{
+					// Insert the new glyph into our own set of glyphs
+					auto pair = glyphs.emplace(character, glyph->WeakCopy());
+					it_glyph = pair.first;
+					if(pair.second)
+						is_layers_dirty = true;
+					break;
+				}
+			}
+
+			// If we still have not found a glyph, use the replacement character.
+			if(it_glyph == glyphs.end())
+			{
+				character = Character::Replacement;
+				it_glyph = glyphs.find(character);
+				if (it_glyph == glyphs.end())
+					return nullptr;
+			}
+		}
+		else
+		{
+			return nullptr;
+		}
+	}
+
+	const FontGlyph* glyph = &it_glyph->second;
+	return glyph;
 }
 
 // Generates (or shares) a layer derived from a font effect.
-FontFaceLayer* FontFaceHandleDefault::GenerateLayer(const SharedPtr<const FontEffect>& font_effect)
+FontFaceLayer* FontFaceHandleDefault::GetOrCreateLayer(const SharedPtr<const FontEffect>& font_effect)
 {
-	// See if this effect has been instanced before, as part of a different configuration.
-	FontLayerMap::iterator i = layers.find(font_effect.get());
-	if (i != layers.end())
-		return i->second;
+	// Try inserting the font effect, it may have been instanced before as part of a different configuration.
+	auto pair = layers.emplace(font_effect.get(), nullptr);
+
+	bool inserted = pair.second;
+	auto& layer = pair.first->second;
 
-	FontFaceLayer* layer = CreateNewLayer();
-	layers[font_effect.get()] = layer;
+	if (!inserted)
+		return layer.get();
+
+	// The new effect was inserted, generate a new layer.
+	layer = std::make_unique<FontFaceLayer>(font_effect);
+	GenerateLayer(layer.get());
+
+	return layer.get();
+}
+
+bool FontFaceHandleDefault::GenerateLayer(FontFaceLayer* layer)
+{
+	RMLUI_ASSERT(layer);
+	const FontEffect* font_effect = layer->GetFontEffect();
+	bool result = false;
 
 	if (!font_effect)
 	{
-		layer->Initialise(this);
+		result = layer->Generate(this);
 	}
 	else
 	{
 		// Determine which, if any, layer the new layer should copy its geometry and textures from.
 		FontFaceLayer* clone = nullptr;
-		bool deep_clone = true;
+		bool clone_glyph_origins = true;
 		String generation_key;
 		size_t fingerprint = font_effect->GetFingerprint();
 
 		if (!font_effect->HasUniqueTexture())
 		{
 			clone = base_layer;
-			deep_clone = false;
+			clone_glyph_origins = false;
 		}
 		else
 		{
-			FontLayerCache::iterator cache_iterator = layer_cache.find(fingerprint);
-			if (cache_iterator != layer_cache.end())
+			auto cache_iterator = layer_cache.find(fingerprint);
+			if (cache_iterator != layer_cache.end() && cache_iterator->second != layer)
 				clone = cache_iterator->second;
 		}
 
 		// Create a new layer.
-		layer->Initialise(this, font_effect, clone, deep_clone);
+		result = layer->Generate(this, clone, clone_glyph_origins);
 
 		// Cache the layer in the layer cache if it generated its own textures (ie, didn't clone).
 		if (!clone)
 			layer_cache[fingerprint] = layer;
 	}
 
-	return layer;
+	return result;
 }
 
-#endif
-
 }
 }

+ 50 - 70
Source/Core/FontFaceHandleDefault.h → Source/Core/FontEngineDefault/FontFaceHandleDefault.h

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -29,63 +29,54 @@
 #ifndef RMLUICOREFONTFACEHANDLE_H
 #define RMLUICOREFONTFACEHANDLE_H
 
-#include "../../Include/RmlUi/Core/Traits.h"
-#include "UnicodeRange.h"
-#include "../../Include/RmlUi/Core/FontEffect.h"
-#include "../../Include/RmlUi/Core/FontGlyph.h"
-#include "../../Include/RmlUi/Core/Geometry.h"
-#include "../../Include/RmlUi/Core/Texture.h"
+#include "../../../Include/RmlUi/Core/Traits.h"
+#include "../../../Include/RmlUi/Core/FontEffect.h"
+#include "../../../Include/RmlUi/Core/FontGlyph.h"
+#include "../../../Include/RmlUi/Core/Geometry.h"
+#include "../../../Include/RmlUi/Core/Texture.h"
+#include "FontTypes.h"
 
 namespace Rml {
 namespace Core {
 
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
 class FontFaceLayer;
 
+
 /**
 	@author Peter Curry
  */
 
-class FontFaceHandleDefault : public NonCopyMoveable
+class FontFaceHandleDefault final : public NonCopyMoveable
 {
 public:
 	FontFaceHandleDefault();
-	virtual ~FontFaceHandleDefault();
+	~FontFaceHandleDefault();
 
-	/// Returns the average advance of all glyphs in this font face.
-	/// @return An approximate width of the characters in this font face.
-	int GetCharacterWidth() const;
+	bool Initialize(FontFaceHandleFreetype face, int font_size);
 
 	/// Returns the point size of this font face.
-	/// @return The face's point size.
 	int GetSize() const;
 	/// Returns the pixel height of a lower-case x in this font face.
-	/// @return The height of a lower-case x.
 	int GetXHeight() const;
 	/// Returns the default height between this font face's baselines.
-	/// @return The default line height.
 	int GetLineHeight() const;
 
 	/// Returns the font's baseline, as a pixel offset from the bottom of the font.
-	/// @return The font's baseline.
 	int GetBaseline() const;
 
 	/// Returns the font's underline, as a pixel offset from the bottom of the font.
-	/// @return The font's underline thickness.
-	float GetUnderline(float *thickness) const;
+	float GetUnderline(float& thickness) const;
 
 	/// Returns the font's glyphs.
-	/// @return The font's glyphs.
-	const FontGlyphList& GetGlyphs() const;
+	const FontGlyphMap& GetGlyphs() const;
 
 	/// Returns the width a string will take up if rendered with this handle.
 	/// @param[in] string The string to measure.
 	/// @param[in] prior_character The optionally-specified character that immediately precedes the string. This may have an impact on the string width due to kerning.
 	/// @return The width, in pixels, this string will occupy if rendered with this handle.
-	int GetStringWidth(const WString& string, word prior_character = 0) const;
+	int GetStringWidth(const String& string, Character prior_character = Character::Null);
 
-	/// Generates, if required, the layer configuration for a given array of font effects.
+	/// Generates, if required, the layer configuration for a given list of font effects.
 	/// @param[in] font_effects The list of font effects to generate the configuration for.
 	/// @return The index to use when generating geometry using this configuration.
 	int GenerateLayerConfiguration(const FontEffectList& font_effects);
@@ -94,7 +85,8 @@ public:
 	/// @param[out] texture_dimensions The dimensions of the texture.
 	/// @param[in] layer_id The id of the layer to request the texture data from.
 	/// @param[in] texture_id The index of the texture within the layer to generate.
-	bool GenerateLayerTexture(const byte*& texture_data, Vector2i& texture_dimensions, FontEffect* layer_id, int texture_id);
+	/// @param[in] handle_version The version of the handle data. Function returns false if out of date.
+	bool GenerateLayerTexture(UniquePtr<const byte[]>& texture_data, Vector2i& texture_dimensions, const FontEffect* layer_id, int texture_id, int handle_version) const;
 
 	/// Generates the geometry required to render a single line of text.
 	/// @param[out] geometry An array of geometries to generate the geometry into.
@@ -102,69 +94,57 @@ public:
 	/// @param[in] position The position of the baseline of the first character to render.
 	/// @param[in] colour The colour to render the text.
 	/// @return The width, in pixels, of the string geometry.
-	int GenerateString(GeometryList& geometry, const WString& string, const Vector2f& position, const Colourb& colour, int layer_configuration = 0) const;
-	/// Generates the geometry required to render a line above, below or through a line of text.
-	/// @param[out] geometry The geometry to append the newly created geometry into.
-	/// @param[in] position The position of the baseline of the lined text.
-	/// @param[in] width The width of the string to line.
-	/// @param[in] decoration_type The type for vertical positioning of line.
-	/// @param[in] colour The colour to draw the line in.
-	void GenerateLine(Geometry* geometry, const Vector2f& position, int width, Style::TextDecoration decoration_type, const Colourb& colour) const;
+	int GenerateString(GeometryList& geometry, const String& string, const Vector2f& position, const Colourb& colour, int layer_configuration = 0);
+
+	/// Version is changed whenever the layers are dirtied, requiring regeneration of string geometry.
+	int GetVersion() const;
+
+
+private:
+	// Build and append glyph to 'glyphs'
+	bool AppendGlyph(Character character);
 
-	/// Returns the font face's raw charset (the charset range as a string).
-	/// @return The font face's charset.
-	const String& GetRawCharset() const;
-	/// Returns the font face's charset.
-	/// @return The font face's charset.
-	const UnicodeRangeList& GetCharset() const;
+	int GetKerning(Character lhs, Character rhs) const;
 
-protected:
+	/// Retrieve a glyph from the given code point, building and appending a new glyph if not already built.
+	/// @param[in-out] character  The character, can be changed e.g. to the replacement character if no glyph is found.
+	/// @param[in] look_in_fallback_fonts  Look for the glyph in fallback fonts if not found locally, adding it to our glyphs.
+	/// @return The font glyph for the returned code point.
+	const FontGlyph* GetOrAppendGlyph(Character& character, bool look_in_fallback_fonts = true);
 
-	virtual int GetKerning(word lhs, word rhs) const = 0;
-	virtual FontFaceLayer* CreateNewLayer();
+	// Regenerate layers if dirty, such as after adding new glyphs.
+	bool UpdateLayersOnDirty();
 
-	FontFaceLayer* GenerateLayer(const SharedPtr<const FontEffect>& font_effect);
+	// Create a new layer from the given font effect if it does not already exist.
+	FontFaceLayer* GetOrCreateLayer(const SharedPtr<const FontEffect>& font_effect);
 
-	typedef std::vector< int > GlyphKerningList;
-	typedef std::vector< GlyphKerningList > FontKerningList;
+	// (Re-)generate a layer in this font face handle.
+	bool GenerateLayer(FontFaceLayer* layer);
 
-	FontGlyphList glyphs;
-	FontKerningList kerning;
+	FontGlyphMap glyphs;
 
-	typedef SmallUnorderedMap< const FontEffect*, FontFaceLayer* > FontLayerMap;
-	typedef SmallUnorderedMap< size_t, FontFaceLayer* > FontLayerCache;
-	typedef std::vector< FontFaceLayer* > LayerConfiguration;
-	typedef std::vector< LayerConfiguration > LayerConfigurationList;
+	using FontLayerMap = SmallUnorderedMap< const FontEffect*, UniquePtr<FontFaceLayer> >;
+	using FontLayerCache = SmallUnorderedMap< size_t, FontFaceLayer* >;
+	using LayerConfiguration = std::vector< FontFaceLayer* >;
+	using LayerConfigurationList = std::vector< LayerConfiguration >;
 
 	// The list of all font layers, index by the effect that instanced them.
 	FontFaceLayer* base_layer;
 	FontLayerMap layers;
-	// Each font layer that generated geometry or textures, indexed by the respective generation
-	// key.
+	// Each font layer that generated geometry or textures, indexed by the respective generation key.
 	FontLayerCache layer_cache;
 
-	// All configurations currently in use on this handle. New configurations will be generated as
-	// required.
-	LayerConfigurationList layer_configurations;
-
-	// The average advance (in pixels) of all of this face's glyphs.
-	int average_advance;
+	int version = 0;
+	bool is_layers_dirty = false;
 
-	int size;
-	int x_height;
-	int line_height;
-	int baseline;
+	// All configurations currently in use on this handle. New configurations will be generated as required.
+	LayerConfigurationList layer_configurations;
 
-	float underline_position;
-	float underline_thickness;
+	FontMetrics metrics;
 
-	String raw_charset;
-	UnicodeRangeList charset;
-	unsigned int max_codepoint;
+	FontFaceHandleFreetype ft_face;
 };
 
-#endif
-
 }
 }
 

+ 82 - 65
Source/Core/FontFaceLayer.cpp → Source/Core/FontEngineDefault/FontFaceLayer.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -28,99 +28,105 @@
 
 #include "precompiled.h"
 #include "FontFaceLayer.h"
-#include "../../Include/RmlUi/Core/Core.h"
 #include "FontFaceHandleDefault.h"
 
 namespace Rml {
 namespace Core {
 
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-	
-FontFaceLayer::FontFaceLayer() : colour(255, 255, 255)
+FontFaceLayer::FontFaceLayer(const SharedPtr<const FontEffect>& _effect) : colour(255, 255, 255)
 {
-	handle = nullptr;
+	effect = _effect;
+	if (effect)
+		colour = effect->GetColour();
 }
 
 FontFaceLayer::~FontFaceLayer()
-{
-}
+{}
 
-// Generates the character and texture data for the layer.
-bool FontFaceLayer::Initialise(const FontFaceHandleDefault* _handle, SharedPtr<const FontEffect> _effect, const FontFaceLayer* clone, bool deep_clone)
+bool FontFaceLayer::Generate(const FontFaceHandleDefault* handle, const FontFaceLayer* clone, bool clone_glyph_origins)
 {
-	handle = _handle;
-	effect = _effect;
-	if (effect)
-		colour = effect->GetColour();
+	// Clear the old layout if it exists.
+	{
+		// @performance: We could be much smarter about this, e.g. such as adding new glyphs to the existing texture layout and textures.
+		// Right now we re-generate the whole thing, including textures.
+		for (auto& texture : textures)
+			texture.RemoveDatabaseCache();
+
+		texture_layout = TextureLayout{};
+		character_boxes.clear();
+		textures.clear();
+	}
 
-	const FontGlyphList& glyphs = handle->GetGlyphs();
+	const FontGlyphMap& glyphs = handle->GetGlyphs();
 
-	// Clone the geometry and textures from the clone layer.
-	if (clone != nullptr)
+	// Generate the new layout.
+	if (clone)
 	{
-		// Copy the cloned layer's characters.
-		characters = clone->characters;
+		// Clone the geometry and textures from the clone layer.
+		character_boxes = clone->character_boxes;
 
-		// Copy (and reference) the cloned layer's textures.
+		// Copy the cloned layer's textures.
 		for (size_t i = 0; i < clone->textures.size(); ++i)
 			textures.push_back(clone->textures[i]);
 
-		// Request the effect (if we have one) adjust the origins as appropriate.
-		if (!deep_clone &&
-			effect != nullptr)
+		// Request the effect (if we have one) and adjust the origins as appropriate.
+		if (effect && !clone_glyph_origins)
 		{
-			for (FontGlyphList::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i)
+			for (auto& pair : glyphs)
 			{
-				const FontGlyph& glyph = *i;
+				Character character = pair.first;
+				const FontGlyph& glyph = pair.second;
 
-				if (glyph.character >= characters.size())
-					continue;
+				RMLUI_ASSERT(character_boxes.find(character) != character_boxes.end());
 
-				Character& character = characters[glyph.character];
+				TextureBox& box = character_boxes[character];
 
-				Vector2i glyph_origin(Math::RealToInteger(character.origin.x), Math::RealToInteger(character.origin.y));
-				Vector2i glyph_dimensions(Math::RealToInteger(character.dimensions.x), Math::RealToInteger(character.dimensions.y));
+				Vector2i glyph_origin(Math::RealToInteger(box.origin.x), Math::RealToInteger(box.origin.y));
+				Vector2i glyph_dimensions(Math::RealToInteger(box.dimensions.x), Math::RealToInteger(box.dimensions.y));
 
 				if (effect->GetGlyphMetrics(glyph_origin, glyph_dimensions, glyph))
 				{
-					character.origin.x = (float) glyph_origin.x;
-					character.origin.y = (float) glyph_origin.y;
+					box.origin.x = (float)glyph_origin.x;
+					box.origin.y = (float)glyph_origin.y;
 				}
 				else
-					character.texture_index = -1;
+					box.texture_index = -1;
 			}
 		}
 	}
 	else
 	{
 		// Initialise the texture layout for the glyphs.
-		characters.resize(glyphs.size(), Character());
-		for (FontGlyphList::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i)
+		character_boxes.reserve(glyphs.size());
+		for (auto& pair : glyphs)
 		{
-			const FontGlyph& glyph = *i;
+			Character character = pair.first;
+			const FontGlyph& glyph = pair.second;
 
 			Vector2i glyph_origin(0, 0);
 			Vector2i glyph_dimensions = glyph.bitmap_dimensions;
 
 			// Adjust glyph origin / dimensions for the font effect.
-			if (effect != nullptr)
+			if (effect)
 			{
 				if (!effect->GetGlyphMetrics(glyph_origin, glyph_dimensions, glyph))
 					continue;
 			}
 
-			Character character;
-			character.origin = Vector2f((float) (glyph_origin.x + glyph.bearing.x), (float) (glyph_origin.y - glyph.bearing.y));
-			character.dimensions = Vector2f((float) glyph_dimensions.x - glyph_origin.x, (float) glyph_dimensions.y - glyph_origin.y);
-			characters[glyph.character] = character;
+			TextureBox box;
+			box.origin = Vector2f((float)(glyph_origin.x + glyph.bearing.x), (float)(glyph_origin.y - glyph.bearing.y));
+			box.dimensions = Vector2f((float)glyph_dimensions.x - glyph_origin.x, (float)glyph_dimensions.y - glyph_origin.y);
+			character_boxes[character] = box;
 
 			// Add the character's dimensions into the texture layout engine.
-			texture_layout.AddRectangle(glyph.character, glyph_dimensions - glyph_origin);
+			texture_layout.AddRectangle((int)character, glyph_dimensions - glyph_origin);
 		}
 
+		constexpr int max_texture_dimensions = 2048;
+
 		// Generate the texture layout; this will position the glyph rectangles efficiently and
 		// allocate the texture data ready for writing.
-		if (!texture_layout.GenerateLayout(512))
+		if (!texture_layout.GenerateLayout(max_texture_dimensions))
 			return false;
 
 
@@ -130,43 +136,49 @@ bool FontFaceLayer::Initialise(const FontFaceHandleDefault* _handle, SharedPtr<c
 		{
 			TextureLayoutRectangle& rectangle = texture_layout.GetRectangle(i);
 			const TextureLayoutTexture& texture = texture_layout.GetTexture(rectangle.GetTextureIndex());
-			Character& character = characters[(word) rectangle.GetId()];
+			Character character = (Character)rectangle.GetId();
+			RMLUI_ASSERT(character_boxes.find(character) != character_boxes.end());
+			TextureBox& box = character_boxes[character];
 
 			// Set the character's texture index.
-			character.texture_index = rectangle.GetTextureIndex();
+			box.texture_index = rectangle.GetTextureIndex();
 
 			// Generate the character's texture coordinates.
-			character.texcoords[0].x = float(rectangle.GetPosition().x) / float(texture.GetDimensions().x);
-			character.texcoords[0].y = float(rectangle.GetPosition().y) / float(texture.GetDimensions().y);
-			character.texcoords[1].x = float(rectangle.GetPosition().x + rectangle.GetDimensions().x) / float(texture.GetDimensions().x);
-			character.texcoords[1].y = float(rectangle.GetPosition().y + rectangle.GetDimensions().y) / float(texture.GetDimensions().y);
+			box.texcoords[0].x = float(rectangle.GetPosition().x) / float(texture.GetDimensions().x);
+			box.texcoords[0].y = float(rectangle.GetPosition().y) / float(texture.GetDimensions().y);
+			box.texcoords[1].x = float(rectangle.GetPosition().x + rectangle.GetDimensions().x) / float(texture.GetDimensions().x);
+			box.texcoords[1].y = float(rectangle.GetPosition().y + rectangle.GetDimensions().y) / float(texture.GetDimensions().y);
 		}
 
+		const FontEffect* effect_ptr = effect.get();
+		const int handle_version = handle->GetVersion();
 
 		// Generate the textures.
 		for (int i = 0; i < texture_layout.GetNumTextures(); ++i)
 		{
-			Texture texture;
-			if (!texture.Load(CreateString(64, "?font::%p/%p/%d", handle, effect.get(), i)))
-				return false;
+			int texture_id = i;
 
+			TextureCallback texture_callback = [handle, effect_ptr, texture_id, handle_version](const String& name, UniquePtr<const byte[]>& data, Vector2i& dimensions) -> bool {
+				bool result = handle->GenerateLayerTexture(data, dimensions, effect_ptr, texture_id, handle_version);
+				return result;
+			};
+
+			Texture texture;
+			texture.Set("font-face-layer", texture_callback);
 			textures.push_back(texture);
 		}
 	}
 
-
 	return true;
 }
 
 // Generates the texture data for a layer (for the texture database).
-bool FontFaceLayer::GenerateTexture(const byte*& texture_data, Vector2i& texture_dimensions, int texture_id)
+bool FontFaceLayer::GenerateTexture(UniquePtr<const byte[]>& texture_data, Vector2i& texture_dimensions, int texture_id, const FontGlyphMap& glyphs)
 {
 	if (texture_id < 0 ||
 		texture_id > texture_layout.GetNumTextures())
 		return false;
 
-	const FontGlyphList& glyphs = handle->GetGlyphs();
-
 	// Generate the texture data.
 	texture_data = texture_layout.GetTexture(texture_id).AllocateTexture();
 	texture_dimensions = texture_layout.GetTexture(texture_id).GetDimensions();
@@ -174,20 +186,27 @@ bool FontFaceLayer::GenerateTexture(const byte*& texture_data, Vector2i& texture
 	for (int i = 0; i < texture_layout.GetNumRectangles(); ++i)
 	{
 		TextureLayoutRectangle& rectangle = texture_layout.GetRectangle(i);
-		Character& character = characters[(word) rectangle.GetId()];	
+		Character character = (Character)rectangle.GetId();
+		RMLUI_ASSERT(character_boxes.find(character) != character_boxes.end());
+
+		TextureBox& box = character_boxes[character];
 
-		if (character.texture_index != texture_id)
+		if (box.texture_index != texture_id)
 			continue;
 
-		const FontGlyph& glyph = glyphs[rectangle.GetId()];
+		auto it = glyphs.find((Character)rectangle.GetId());
+		if (it == glyphs.end())
+			continue;
+
+		const FontGlyph& glyph = it->second;
 
 		if (effect == nullptr)
 		{
 			// Copy the glyph's bitmap data into its allocated texture.
-			if (glyph.bitmap_data != nullptr)
+			if (glyph.bitmap_data)
 			{
 				byte* destination = rectangle.GetTextureData();
-				byte* source = glyph.bitmap_data;
+				const byte* source = glyph.bitmap_data;
 
 				for (int j = 0; j < glyph.bitmap_dimensions.y; ++j)
 				{
@@ -201,7 +220,7 @@ bool FontFaceLayer::GenerateTexture(const byte*& texture_data, Vector2i& texture
 		}
 		else
 		{
-			effect->GenerateGlyphTexture(rectangle.GetTextureData(), Vector2i(Math::RealToInteger(character.dimensions.x), Math::RealToInteger(character.dimensions.y)), rectangle.GetTextureStride(), glyph);
+			effect->GenerateGlyphTexture(rectangle.GetTextureData(), Vector2i(Math::RealToInteger(box.dimensions.x), Math::RealToInteger(box.dimensions.y)), rectangle.GetTextureStride(), glyph);
 		}
 	}
 
@@ -226,7 +245,7 @@ const Texture* FontFaceLayer::GetTexture(int index)
 // Returns the number of textures employed by this layer.
 int FontFaceLayer::GetNumTextures() const
 {
-	return (int) textures.size();
+	return (int)textures.size();
 }
 
 // Returns the layer's colour.
@@ -235,7 +254,5 @@ const Colourb& FontFaceLayer::GetColour() const
 	return colour;
 }
 
-#endif
-
 }
 }

+ 36 - 42
Source/Core/FontFaceLayer.h → Source/Core/FontEngineDefault/FontFaceLayer.h

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -29,23 +29,21 @@
 #ifndef RMLUICOREFONTFACELAYER_H
 #define RMLUICOREFONTFACELAYER_H
 
-#include "../../Include/RmlUi/Core/FontGlyph.h"
-#include "../../Include/RmlUi/Core/Geometry.h"
-#include "../../Include/RmlUi/Core/GeometryUtilities.h"
-#include "../../Include/RmlUi/Core/Texture.h"
-#include "TextureLayout.h"
+#include "../../../Include/RmlUi/Core/FontGlyph.h"
+#include "../../../Include/RmlUi/Core/Geometry.h"
+#include "../../../Include/RmlUi/Core/GeometryUtilities.h"
+#include "../../../Include/RmlUi/Core/Texture.h"
+#include "../TextureLayout.h"
 
 namespace Rml {
 namespace Core {
 
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
 class FontEffect;
 class FontFaceHandleDefault;
 
 /**
 	A textured layer stored as part of a font face handle. Each handle will have at least a base
-	layer for the standard font. Further layers can be added to allow to rendering of text effects.
+	layer for the standard font. Further layers can be added to allow rendering of text effects.
 
 	@author Peter Curry
  */
@@ -53,75 +51,74 @@ class FontFaceHandleDefault;
 class FontFaceLayer
 {
 public:
-	FontFaceLayer();
-	virtual ~FontFaceLayer();
+	FontFaceLayer(const SharedPtr<const FontEffect>& _effect);
+	~FontFaceLayer();
 
-	/// Generates the character and texture data for the layer.
+	/// Generates or re-generates the character and texture data for the layer.
 	/// @param[in] handle The handle generating this layer.
 	/// @param[in] effect The effect to initialise the layer with.
 	/// @param[in] clone The layer to optionally clone geometry and texture data from.
-	/// @param[in] deep_clone If true, the clones geometry will be completely cloned and the effect will have no option to affect even the glyph origins.
 	/// @return True if the layer was generated successfully, false if not.
-	virtual bool Initialise(const FontFaceHandleDefault* handle, SharedPtr<const FontEffect> effect = {}, const FontFaceLayer* clone = nullptr, bool deep_clone = false);
+	bool Generate(const FontFaceHandleDefault* handle, const FontFaceLayer* clone = nullptr, bool clone_glyph_origins = false);
 
 	/// Generates the texture data for a layer (for the texture database).
 	/// @param[out] texture_data The pointer to be set to the generated texture data.
 	/// @param[out] texture_dimensions The dimensions of the texture.
-	/// @param[in] glyphs The glyphs required by the font face handle.
 	/// @param[in] texture_id The index of the texture within the layer to generate.
-	virtual bool GenerateTexture(const byte*& texture_data, Vector2i& texture_dimensions, int texture_id);
+	/// @param[in] glyphs The glyphs required by the font face handle.
+	bool GenerateTexture(UniquePtr<const byte[]>& texture_data, Vector2i& texture_dimensions, int texture_id, const FontGlyphMap& glyphs);
+
 	/// Generates the geometry required to render a single character.
 	/// @param[out] geometry An array of geometries this layer will write to. It must be at least as big as the number of textures in this layer.
 	/// @param[in] character_code The character to generate geometry for.
 	/// @param[in] position The position of the baseline.
 	/// @param[in] colour The colour of the string.
-	inline void GenerateGeometry(Geometry* geometry, const word character_code, const Vector2f& position, const Colourb& colour) const
+	inline void GenerateGeometry(Geometry* geometry, const Character character_code, const Vector2f& position, const Colourb& colour) const
 	{
-		if (character_code >= characters.size())
+		auto it = character_boxes.find(character_code);
+		if (it == character_boxes.end())
 			return;
 
-		const Character& character = characters[character_code];
-		if (character.texture_index < 0)
+		const TextureBox& box = it->second;
+
+		if (box.texture_index < 0)
 			return;
 
 		// Generate the geometry for the character.
-		std::vector< Vertex >& character_vertices = geometry[character.texture_index].GetVertices();
-		std::vector< int >& character_indices = geometry[character.texture_index].GetIndices();
+		std::vector< Vertex >& character_vertices = geometry[box.texture_index].GetVertices();
+		std::vector< int >& character_indices = geometry[box.texture_index].GetIndices();
 
 		character_vertices.resize(character_vertices.size() + 4);
 		character_indices.resize(character_indices.size() + 6);
 		GeometryUtilities::GenerateQuad(
 			&character_vertices[0] + (character_vertices.size() - 4),
 			&character_indices[0] + (character_indices.size() - 6),
-			Vector2f(position.x + character.origin.x, position.y + character.origin.y).Round(),
-			character.dimensions,
-			colour, 
-			character.texcoords[0],
-			character.texcoords[1],
+			Vector2f(position.x + box.origin.x, position.y + box.origin.y).Round(),
+			box.dimensions,
+			colour,
+			box.texcoords[0],
+			box.texcoords[1],
 			(int)character_vertices.size() - 4
 		);
 	}
 
 	/// Returns the effect used to generate the layer.
-	/// @return The layer's effect.
 	const FontEffect* GetFontEffect() const;
 
-	/// Returns on the layer's textures.
-	/// @param[in] index The index of the desired texture.
-	/// @return The requested texture.
+	/// Returns one of the layer's textures.
 	const Texture* GetTexture(int index);
 	/// Returns the number of textures employed by this layer.
-	/// @return The number of used textures.
 	int GetNumTextures() const;
 
 	/// Returns the layer's colour.
-	/// @return The layer's colour.
 	const Colourb& GetColour() const;
 
-// protected:
-	struct Character
+private:
+
+
+	struct TextureBox
 	{
-		Character() : texture_index(-1) { }
+		TextureBox() : texture_index(-1) { }
 
 		// The offset, in pixels, of the baseline from the start of this character's geometry.
 		Vector2f origin;
@@ -134,21 +131,18 @@ public:
 		int texture_index;
 	};
 
-	typedef std::vector< Character > CharacterList;
-	typedef std::vector< Texture > TextureList;
+	using CharacterMap = UnorderedMap<Character, TextureBox>;
+	using TextureList = std::vector<Texture>;
 
-	const FontFaceHandleDefault* handle;
 	SharedPtr<const FontEffect> effect;
 
 	TextureLayout texture_layout;
 
-	CharacterList characters;
+	CharacterMap character_boxes;
 	TextureList textures;
 	Colourb colour;
 };
 
-#endif
-
 }
 }
 

+ 16 - 10
Source/Core/FontFamily.cpp → Source/Core/FontEngineDefault/FontFamily.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -37,14 +37,8 @@ FontFamily::FontFamily(const String& name) : name(name)
 {
 }
 
-FontFamily::~FontFamily()
-{
-	for (size_t i = 0; i < font_faces.size(); ++i)
-		delete font_faces[i];
-}
-
 // Returns a handle to the most appropriate font in the family, at the correct size.
-SharedPtr<FontFaceHandleDefault> FontFamily::GetFaceHandle(const String& charset, Style::FontStyle style, Style::FontWeight weight, int size)
+FontFaceHandleDefault* FontFamily::GetFaceHandle(Style::FontStyle style, Style::FontWeight weight, int size)
 {
 	// Search for a face of the same style, and match the weight as closely as we can.
 	FontFace* matching_face = nullptr;
@@ -54,7 +48,7 @@ SharedPtr<FontFaceHandleDefault> FontFamily::GetFaceHandle(const String& charset
 		// if it's a perfect match, then we'll stop looking altogether.
 		if (font_faces[i]->GetStyle() == style)
 		{
-			matching_face = font_faces[i];
+			matching_face = font_faces[i].get();
 
 			if (font_faces[i]->GetWeight() == weight)
 				break;
@@ -64,7 +58,19 @@ SharedPtr<FontFaceHandleDefault> FontFamily::GetFaceHandle(const String& charset
 	if (matching_face == nullptr)
 		return nullptr;
 
-	return matching_face->GetHandle(charset, size);
+	return matching_face->GetHandle(size);
+}
+
+
+// Adds a new face to the family.
+FontFace* FontFamily::AddFace(FontFaceHandleFreetype ft_face, Style::FontStyle style, Style::FontWeight weight, bool release_stream)
+{
+	auto face = std::make_unique<FontFace>(ft_face, style, weight, release_stream);
+	FontFace* result = face.get();
+
+	font_faces.push_back(std::move(face));
+
+	return result;
 }
 
 }

+ 12 - 13
Source/Core/FontFamily.h → Source/Core/FontEngineDefault/FontFamily.h

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -29,7 +29,7 @@
 #ifndef RMLUICOREFONTFAMILY_H
 #define RMLUICOREFONTFAMILY_H
 
-#include <RmlUi/Core/StringUtilities.h>
+#include "FontTypes.h"
 
 namespace Rml {
 namespace Core {
@@ -45,7 +45,14 @@ class FontFamily
 {
 public:
 	FontFamily(const String& name);
-    virtual ~FontFamily();
+
+	/// Returns a handle to the most appropriate font in the family, at the correct size.
+	/// @param[in] style The style of the desired handle.
+	/// @param[in] weight The weight of the desired handle.
+	/// @param[in] size The size of desired handle, in points.
+	/// @return A valid handle if a matching (or closely matching) font face was found, nullptr otherwise.
+	FontFaceHandleDefault* GetFaceHandle(Style::FontStyle style, Style::FontWeight weight, int size);
+
 
 	/// Adds a new face to the family.
 	/// @param[in] ft_face The previously loaded FreeType face.
@@ -53,20 +60,12 @@ public:
 	/// @param[in] weight The weight of the new face.
 	/// @param[in] release_stream True if the application must free the face's memory stream.
 	/// @return True if the face was loaded successfully, false otherwise.
-    virtual bool AddFace(void* ft_face, Style::FontStyle style, Style::FontWeight weight, bool release_stream) = 0;
-
-	/// Returns a handle to the most appropriate font in the family, at the correct size.
-	/// @param[in] charset The set of characters in the handle, as a comma-separated list of unicode ranges.
-	/// @param[in] style The style of the desired handle.
-	/// @param[in] weight The weight of the desired handle.
-	/// @param[in] size The size of desired handle, in points.
-	/// @return A valid handle if a matching (or closely matching) font face was found, nullptr otherwise.
-	SharedPtr<FontFaceHandleDefault> GetFaceHandle(const String& charset, Style::FontStyle style, Style::FontWeight weight, int size);
+	FontFace* AddFace(FontFaceHandleFreetype ft_face, Style::FontStyle style, Style::FontWeight weight, bool release_stream);
 
 protected:
 	String name;
 
-	typedef std::vector< FontFace* > FontFaceList;
+	using FontFaceList = std::vector< UniquePtr<FontFace> >;
 	FontFaceList font_faces;
 };
 

+ 195 - 0
Source/Core/FontEngineDefault/FontProvider.cpp

@@ -0,0 +1,195 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include "FontProvider.h"
+#include "FontFace.h"
+#include "FontFamily.h"
+#include "FreeTypeInterface.h"
+
+namespace Rml {
+namespace Core {
+
+static FontProvider* g_font_provider = nullptr;
+
+FontProvider::FontProvider()
+{
+	RMLUI_ASSERT(!g_font_provider);
+}
+
+FontProvider::~FontProvider()
+{
+	RMLUI_ASSERT(g_font_provider == this);
+}
+
+bool FontProvider::Initialise()
+{
+	RMLUI_ASSERT(!g_font_provider);
+	if (!FreeType::Initialise())
+		return false;
+	g_font_provider = new FontProvider;
+	return true;
+}
+
+void FontProvider::Shutdown()
+{
+	RMLUI_ASSERT(g_font_provider);
+	delete g_font_provider;
+	g_font_provider = nullptr;
+	FreeType::Shutdown();
+}
+
+FontProvider& FontProvider::Get()
+{
+	RMLUI_ASSERT(g_font_provider);
+	return *g_font_provider;
+}
+
+FontFaceHandleDefault* FontProvider::GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size)
+{
+	RMLUI_ASSERTMSG(family == StringUtilities::ToLower(family), "Font family name must be converted to lowercase before entering here.");
+
+	FontFamilyMap& families = Get().font_families;
+
+	auto it = families.find(family);
+	if (it == families.end())
+		return nullptr;
+
+	return it->second->GetFaceHandle(style, weight, size);
+}
+
+int FontProvider::CountFallbackFontFaces()
+{
+	return (int)Get().fallback_font_faces.size();
+}
+
+FontFaceHandleDefault* FontProvider::GetFallbackFontFace(int index, int font_size)
+{
+	auto& faces = FontProvider::Get().fallback_font_faces;
+
+	if (index >= 0 && index < (int)faces.size())
+		return faces[index]->GetHandle(font_size);
+
+	return nullptr;
+}
+
+
+bool FontProvider::LoadFontFace(const String& file_name, bool fallback_face)
+{
+	FileInterface* file_interface = GetFileInterface();
+	FileHandle handle = file_interface->Open(file_name);
+
+	if (!handle)
+	{
+		Log::Message(Log::LT_ERROR, "Failed to load font face from %s, could not open file.", file_name.c_str());
+		return false;
+	}
+
+	size_t length = file_interface->Length(handle);
+
+	byte* buffer = new byte[length];
+	file_interface->Read(buffer, length, handle);
+	file_interface->Close(handle);
+
+	bool result = Get().LoadFontFace(buffer, (int)length, fallback_face, true, file_name);
+
+	return result;
+}
+
+
+bool FontProvider::LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face)
+{
+	const String source = "memory";
+	
+	bool result = Get().LoadFontFace(data, data_size, fallback_face, false, source, font_family, style, weight);
+	
+	return result;
+}
+
+bool FontProvider::LoadFontFace(const byte* data, int data_size, bool fallback_face, bool local_data, const String& source,
+	String font_family, Style::FontStyle style, Style::FontWeight weight)
+{
+	FontFaceHandleFreetype ft_face = FreeType::LoadFace(data, data_size, source);
+	
+	if (!ft_face)
+	{
+		if (local_data)
+			delete[] data;
+
+		Log::Message(Log::LT_ERROR, "Failed to load font face %s (from %s).", font_family.c_str(), source.c_str());
+		return false;
+	}
+
+	if (font_family.empty())
+	{
+		FreeType::GetFaceStyle(ft_face, font_family, style, weight);
+	}
+
+	if (!AddFace(ft_face, font_family, style, weight, fallback_face, local_data))
+	{
+		Log::Message(Log::LT_ERROR, "Failed to load font face %s (from %s).", font_family.c_str(), source.c_str());
+		return false;
+	}
+
+	Log::Message(Log::LT_INFO, "Loaded font face %s (from %s).", font_family.c_str(), source.c_str());
+	return true;
+}
+
+bool FontProvider::AddFace(FontFaceHandleFreetype face, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face, bool release_stream)
+{
+	String family_lower = StringUtilities::ToLower(family);
+	FontFamily* font_family = nullptr;
+	auto it = font_families.find(family_lower);
+	if (it != font_families.end())
+	{
+		font_family = (FontFamily*)it->second.get();
+	}
+	else
+	{
+		auto font_family_ptr = std::make_unique<FontFamily>(family_lower);
+		font_family = font_family_ptr.get();
+		font_families[family_lower] = std::move(font_family_ptr);
+	}
+
+	FontFace* font_face_result = font_family->AddFace(face, style, weight, release_stream);
+
+	if (font_face_result && fallback_face)
+	{
+		auto it_fallback_face = std::find(fallback_font_faces.begin(), fallback_font_faces.end(), font_face_result);
+		if (it_fallback_face == fallback_font_faces.end())
+		{
+			fallback_font_faces.push_back(font_face_result);
+		}
+	}
+
+	return static_cast<bool>(font_face_result);
+}
+
+
+}
+}

+ 35 - 37
Source/Core/FontDatabaseDefault.h → Source/Core/FontEngineDefault/FontProvider.h

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,75 +26,73 @@
  *
  */
 
-#ifndef RMLUICOREFONTDATABASE_H
-#define RMLUICOREFONTDATABASE_H
+#ifndef RMLUICOREFONTPROVIDER_H
+#define RMLUICOREFONTPROVIDER_H
 
-#include <RmlUi/Core/StringUtilities.h>
-#include <RmlUi/Core/Header.h>
-#include "FontProvider.h"
+#include "../../../Include/RmlUi/Core/Types.h"
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
+#include "FontTypes.h"
 
 namespace Rml {
 namespace Core {
 
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-class FontEffect;
+class FontFace;
 class FontFamily;
 class FontFaceHandleDefault;
-class PropertyDictionary;
 
 /**
-	The font database contains all font families currently in use by RmlUi.
-
+	The font provider contains all font families currently in use by RmlUi.
 	@author Peter Curry
  */
 
-class RMLUICORE_API FontDatabaseDefault
+class FontProvider
 {
 public:
-
-    enum FontProviderType
-    {
-        FreeType = 0,
-        BitmapFont
-    };
-
 	static bool Initialise();
 	static void Shutdown();
 
-	/// Adds a new font face to the database. The face's family, style and weight will be determined from the face itself.
-	/// @param[in] file_name The file to load the face from.
-	/// @return True if the face was loaded successfully, false otherwise.
-	static bool LoadFontFace(const String& file_name);
-
 	/// Returns a handle to a font face that can be used to position and render text. This will return the closest match
 	/// it can find, but in the event a font family is requested that does not exist, nullptr will be returned instead of a
 	/// valid handle.
 	/// @param[in] family The family of the desired font handle.
-	/// @param[in] charset The set of characters required in the font face, as a comma-separated list of unicode ranges.
 	/// @param[in] style The style of the desired font handle.
 	/// @param[in] weight The weight of the desired font handle.
 	/// @param[in] size The size of desired handle, in points.
 	/// @return A valid handle if a matching (or closely matching) font face was found, nullptr otherwise.
-	static SharedPtr<FontFaceHandleDefault> GetFontFaceHandle(const String& family, const String& charset, Style::FontStyle style, Style::FontWeight weight, int size);
+	static FontFaceHandleDefault* GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size);
 
-    static void AddFontProvider(FontProvider * provider);
+	/// Adds a new font face to the database. The face's family, style and weight will be determined from the face itself.
+	static bool LoadFontFace(const String& file_name, bool fallback_face);
 
-    static void RemoveFontProvider(FontProvider * provider);
+	/// Adds a new font face from memory.
+	static bool LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face);
+
+	/// Return the number of fallback font faces.
+	static int CountFallbackFontFaces();
+
+	/// Return a font face handle with the given index, at the given font size.
+	static FontFaceHandleDefault* GetFallbackFontFace(int index, int font_size);
 
 private:
-	FontDatabaseDefault(void);
-	~FontDatabaseDefault(void);
+	FontProvider();
+	~FontProvider();
 
-    static FontProviderType GetFontProviderType(const String& file_name);
+	static FontProvider& Get();
 
-    typedef std::vector< FontProvider *> FontProviderTable;
+	bool LoadFontFace(const byte* data, int data_size, bool fallback_face, bool local_data, const String& source,
+		String font_family = {}, Style::FontStyle style = Style::FontStyle::Normal, Style::FontWeight weight = Style::FontWeight::Normal);
 
-    static FontProviderTable font_provider_table;
-	static FontDatabaseDefault* instance;
-};
+	bool AddFace(FontFaceHandleFreetype face, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face, bool release_stream);
 
-#endif
+	using FontFaceList = std::vector<FontFace*>;
+	using FontFamilyMap = UnorderedMap< String, UniquePtr<FontFamily>>;
+
+	FontFamilyMap font_families;
+	FontFaceList fallback_font_faces;
+
+	static const String debugger_font_family_name;
+	
+};
 
 }
 }

+ 22 - 6
Source/Core/FreeType/precompiled.h → Source/Core/FontEngineDefault/FontTypes.h

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- *
+ * 
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,13 +26,29 @@
  *
  */
 
-#ifndef RMLUICOREFREETYPEFONTPRECOMPILED_H
-#define RMLUICOREFREETYPEFONTPRECOMPILED_H
+#ifndef RMLUICOREFONTTYPES_H
+#define RMLUICOREFONTTYPES_H
 
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
+#include "../../../Include/RmlUi/Core/Types.h"
 
-#include "../precompiled.h"
+namespace Rml {
+namespace Core {
 
-#endif
+
+using FontFaceHandleFreetype = uintptr_t;
+
+struct FontMetrics 
+{
+	int size;
+	int x_height;
+	int line_height;
+	int baseline;
+
+	float underline_position;
+	float underline_thickness;
+};
+
+}
+}
 
 #endif

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

@@ -0,0 +1,378 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+
+#include "FreeTypeInterface.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace Rml {
+namespace Core {
+
+static FT_Library ft_library = nullptr;
+
+
+static bool BuildGlyph(FT_Face ft_face, Character character, FontGlyphMap& glyphs);
+static void BuildGlyphMap(FT_Face ft_face, int size, FontGlyphMap& glyphs);
+static void GenerateMetrics(FT_Face ft_face, const FontGlyphMap& glyphs, FontMetrics& metrics);
+
+
+bool FreeType::Initialise()
+{
+	RMLUI_ASSERT(!ft_library);
+
+	FT_Error result = FT_Init_FreeType(&ft_library);
+	if (result != 0)
+	{
+		Log::Message(Log::LT_ERROR, "Failed to initialise FreeType, error %d.", result);
+		Shutdown();
+		return false;
+	}
+
+	return true;
+}
+
+void FreeType::Shutdown()
+{
+	if (ft_library != nullptr)
+	{
+		FT_Done_FreeType(ft_library);
+		ft_library = nullptr;
+	}
+}
+
+// Loads a FreeType face from memory.
+FontFaceHandleFreetype FreeType::LoadFace(const byte* data, int data_length, const String& source)
+{
+	RMLUI_ASSERT(ft_library);
+
+	FT_Face face = nullptr;
+	int error = FT_New_Memory_Face(ft_library, (const FT_Byte*)data, data_length, 0, &face);
+	if (error != 0)
+	{
+		Log::Message(Log::LT_ERROR, "FreeType error %d while loading face from %s.", error, source.c_str());
+		return 0;
+	}
+
+	// Initialise the character mapping on the face.
+	if (face->charmap == nullptr)
+	{
+		FT_Select_Charmap(face, FT_ENCODING_APPLE_ROMAN);
+		if (face->charmap == nullptr)
+		{
+			Log::Message(Log::LT_ERROR, "Font face (from %s) does not contain a Unicode or Apple Roman character map.", source.c_str());
+			FT_Done_Face(face);
+			return 0;
+		}
+	}
+
+	return (FontFaceHandleFreetype)face;
+}
+
+bool FreeType::ReleaseFace(FontFaceHandleFreetype in_face, bool release_stream)
+{
+	FT_Face face = (FT_Face)in_face;
+
+	FT_Byte* face_memory = face->stream->base;
+	FT_Error error = FT_Done_Face(face);
+
+	if (release_stream)
+		delete[] face_memory;
+
+	return (error == 0);
+}
+
+void FreeType::GetFaceStyle(FontFaceHandleFreetype in_face, String& font_family, Style::FontStyle& style, Style::FontWeight& weight)
+{
+	FT_Face face = (FT_Face)in_face;
+
+	font_family = face->family_name;
+	style = face->style_flags & FT_STYLE_FLAG_ITALIC ? Style::FontStyle::Italic : Style::FontStyle::Normal;
+	weight = face->style_flags & FT_STYLE_FLAG_BOLD ? Style::FontWeight::Bold : Style::FontWeight::Normal;
+}
+
+
+
+// Initialises the handle so it is able to render text.
+bool FreeType::InitialiseFaceHandle(FontFaceHandleFreetype face, int font_size, FontGlyphMap& glyphs, FontMetrics& metrics)
+{
+	FT_Face ft_face = (FT_Face)face;
+
+	metrics.size = font_size;
+
+	// Set the character size on the font face.
+	FT_Error error = FT_Set_Char_Size(ft_face, 0, font_size << 6, 0, 0);
+	if (error != 0)
+	{
+		Log::Message(Log::LT_ERROR, "Unable to set the character size '%d' on the font face '%s %s'.", font_size, ft_face->family_name, ft_face->style_name);
+		return false;
+	}
+
+	// Construct the initial list of glyphs.
+	BuildGlyphMap(ft_face, font_size, glyphs);
+
+	// Generate the metrics for the handle.
+	GenerateMetrics(ft_face, glyphs, metrics);
+
+	return true;
+}
+
+bool FreeType::AppendGlyph(FontFaceHandleFreetype face, int font_size, Character character, FontGlyphMap& glyphs)
+{
+	FT_Face ft_face = (FT_Face)face;
+
+	RMLUI_ASSERT(glyphs.find(character) == glyphs.end());
+	RMLUI_ASSERT(ft_face);
+
+	// Set face size again in case it was used at another size in another font face handle.
+	FT_Error error = FT_Set_Char_Size(ft_face, 0, font_size << 6, 0, 0);
+	if (error != 0)
+	{
+		Log::Message(Log::LT_ERROR, "Unable to set the character size '%d' on the font face '%s %s'.", font_size, ft_face->family_name, ft_face->style_name);
+		return false;
+	}
+
+	if (!BuildGlyph(ft_face, character, glyphs))
+		return false;
+
+	return true;
+}
+
+
+int FreeType::GetKerning(FontFaceHandleFreetype face, int font_size, Character lhs, Character rhs)
+{
+	FT_Face ft_face = (FT_Face)face;
+
+	if (!FT_HAS_KERNING(ft_face))
+		return 0;
+
+	// Set face size again in case it was used at another size in another font face handle.
+	FT_Error ft_error = FT_Set_Char_Size(ft_face, 0, font_size << 6, 0, 0);
+	if (ft_error)
+		return 0;
+
+	FT_Vector ft_kerning;
+
+	ft_error = FT_Get_Kerning(
+		ft_face,
+		FT_Get_Char_Index(ft_face, (FT_ULong)lhs),
+		FT_Get_Char_Index(ft_face, (FT_ULong)rhs),
+		FT_KERNING_DEFAULT,
+		&ft_kerning
+	);
+
+	if (ft_error)
+		return 0;
+
+	int kerning = ft_kerning.x >> 6;
+	return kerning;
+}
+
+
+
+static void BuildGlyphMap(FT_Face ft_face, int size, FontGlyphMap& glyphs)
+{
+	glyphs.reserve(128);
+
+	// Add the ASCII characters now. Other characters are added later as needed.
+	FT_ULong code_min = 32;
+	FT_ULong code_max = 126;
+
+	for (FT_ULong character_code = code_min; character_code <= code_max; ++character_code)
+		BuildGlyph(ft_face, (Character)character_code, glyphs);
+
+	// Add a replacement character for rendering unknown characters.
+	Character replacement_character = Character::Replacement;
+	auto it = glyphs.find(replacement_character);
+	if (it == glyphs.end())
+	{
+		FontGlyph glyph;
+		glyph.dimensions = { size / 3, (size * 2) / 3 };
+		glyph.bitmap_dimensions = glyph.dimensions;
+		glyph.advance = glyph.dimensions.x + 2;
+		glyph.bearing = { 1, glyph.dimensions.y };
+
+		glyph.bitmap_owned_data.reset(new byte[glyph.bitmap_dimensions.x * glyph.bitmap_dimensions.y]);
+		glyph.bitmap_data = glyph.bitmap_owned_data.get();
+
+		for (int y = 0; y < glyph.bitmap_dimensions.y; y++)
+		{
+			for (int x = 0; x < glyph.bitmap_dimensions.x; x++)
+			{
+				constexpr int stroke = 1;
+				int i = y * glyph.bitmap_dimensions.x + x;
+				bool near_edge = (x < stroke || x >= glyph.bitmap_dimensions.x - stroke || y < stroke || y >= glyph.bitmap_dimensions.y - stroke);
+				glyph.bitmap_owned_data[i] = (near_edge ? 0xdd : 0);
+			}
+		}
+
+		glyphs[replacement_character] = std::move(glyph);
+	}
+}
+
+static bool BuildGlyph(FT_Face ft_face, Character character, FontGlyphMap& glyphs)
+{
+	int index = FT_Get_Char_Index(ft_face, (FT_ULong)character);
+	if (index == 0)
+		return false;
+
+	FT_Error error = FT_Load_Glyph(ft_face, index, 0);
+	if (error != 0)
+	{
+		Log::Message(Log::LT_WARNING, "Unable to load glyph for character '%u' on the font face '%s %s'; error code: %d.", character, ft_face->family_name, ft_face->style_name, error);
+		return false;
+	}
+
+	error = FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_NORMAL);
+	if (error != 0)
+	{
+		Log::Message(Log::LT_WARNING, "Unable to render glyph for character '%u' on the font face '%s %s'; error code: %d.", character, ft_face->family_name, ft_face->style_name, error);
+		return false;
+	}
+
+	auto result = glyphs.emplace(character, FontGlyph{});
+	if (!result.second)
+	{
+		Log::Message(Log::LT_WARNING, "Glyph character '%u' is already loaded in the font face '%s %s'.", character, ft_face->family_name, ft_face->style_name);
+		return false;
+	}
+
+	FontGlyph& glyph = result.first->second;
+
+	FT_GlyphSlot ft_glyph = ft_face->glyph;
+
+	// Set the glyph's dimensions.
+	glyph.dimensions.x = ft_glyph->metrics.width >> 6;
+	glyph.dimensions.y = ft_glyph->metrics.height >> 6;
+
+	// Set the glyph's bearing.
+	glyph.bearing.x = ft_glyph->metrics.horiBearingX >> 6;
+	glyph.bearing.y = ft_glyph->metrics.horiBearingY >> 6;
+
+	// Set the glyph's advance.
+	glyph.advance = ft_glyph->metrics.horiAdvance >> 6;
+
+	// Set the glyph's bitmap dimensions.
+	glyph.bitmap_dimensions.x = ft_glyph->bitmap.width;
+	glyph.bitmap_dimensions.y = ft_glyph->bitmap.rows;
+
+	// Copy the glyph's bitmap data from the FreeType glyph handle to our glyph handle.
+	if (glyph.bitmap_dimensions.x * glyph.bitmap_dimensions.y != 0)
+	{
+		// Check the pixel mode is supported.
+		if (ft_glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO &&
+			ft_glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
+		{
+			glyph.bitmap_owned_data.reset();
+			glyph.bitmap_data = nullptr;
+			Log::Message(Log::LT_WARNING, "Unable to render glyph on the font face '%s %s'; unsupported pixel mode (%d).", ft_glyph->face->family_name, ft_glyph->face->style_name, ft_glyph->bitmap.pixel_mode);
+		}
+		else
+		{
+			glyph.bitmap_owned_data.reset(new byte[glyph.bitmap_dimensions.x * glyph.bitmap_dimensions.y]);
+			glyph.bitmap_data = glyph.bitmap_owned_data.get();
+
+			const byte* source_bitmap = ft_glyph->bitmap.buffer;
+			byte* destination_bitmap = glyph.bitmap_owned_data.get();
+
+			// Copy the bitmap data into the newly-allocated space on our glyph.
+			switch (ft_glyph->bitmap.pixel_mode)
+			{
+				// Unpack 1-bit data into 8-bit.
+			case FT_PIXEL_MODE_MONO:
+			{
+				for (int i = 0; i < glyph.bitmap_dimensions.y; ++i)
+				{
+					int mask = 0x80;
+					const byte* source_byte = source_bitmap;
+					for (int j = 0; j < glyph.bitmap_dimensions.x; ++j)
+					{
+						if ((*source_byte & mask) == mask)
+							destination_bitmap[j] = 255;
+						else
+							destination_bitmap[j] = 0;
+
+						mask >>= 1;
+						if (mask <= 0)
+						{
+							mask = 0x80;
+							++source_byte;
+						}
+					}
+
+					destination_bitmap += glyph.bitmap_dimensions.x;
+					source_bitmap += ft_glyph->bitmap.pitch;
+				}
+			}
+			break;
+
+			// Directly copy 8-bit data.
+			case FT_PIXEL_MODE_GRAY:
+			{
+				for (int i = 0; i < glyph.bitmap_dimensions.y; ++i)
+				{
+					memcpy(destination_bitmap, source_bitmap, glyph.bitmap_dimensions.x);
+					destination_bitmap += glyph.bitmap_dimensions.x;
+					source_bitmap += ft_glyph->bitmap.pitch;
+				}
+			}
+			break;
+			}
+		}
+	}
+	else
+	{
+		glyph.bitmap_owned_data.reset();
+		glyph.bitmap_data = nullptr;
+	}
+
+	return true;
+}
+
+static void GenerateMetrics(FT_Face ft_face, const FontGlyphMap& glyphs, FontMetrics& metrics)
+{
+	metrics.line_height = ft_face->size->metrics.height >> 6;
+	metrics.baseline = metrics.line_height - (ft_face->size->metrics.ascender >> 6);
+
+	metrics.underline_position = FT_MulFix(ft_face->underline_position, ft_face->size->metrics.y_scale) / float(1 << 6);
+	metrics.underline_thickness = FT_MulFix(ft_face->underline_thickness, ft_face->size->metrics.y_scale) / float(1 << 6);
+	metrics.underline_thickness = Math::Max(metrics.underline_thickness, 1.0f);
+
+	// Determine the x-height of this font face.
+	int index = FT_Get_Char_Index(ft_face, 'x');
+	if (FT_Load_Glyph(ft_face, index, 0) == 0)
+		metrics.x_height = ft_face->glyph->metrics.height >> 6;
+	else
+		metrics.x_height = 0;
+}
+
+
+}
+}

+ 22 - 27
Source/Core/FreeType/FontFamily.h → Source/Core/FontEngineDefault/FreeTypeInterface.h

@@ -26,45 +26,40 @@
  *
  */
 
-#ifndef RMLUICOREFREETYPEFONTFAMILY_H
-#define RMLUICOREFREETYPEFONTFAMILY_H
+#ifndef RMLUICOREFREETYPEINTERFACE_H
+#define RMLUICOREFREETYPEINTERFACE_H
 
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
-
-#include "../FontFamily.h"
-#include <ft2build.h>
-#include FT_FREETYPE_H
+#include "FontTypes.h"
 
 namespace Rml {
 namespace Core {
+namespace FreeType {
 
-class FontFace;
+// Initialize FreeType library.
+bool Initialise();
+// Shutdown FreeType library.
+void Shutdown();
 
-/**
-	@author Peter Curry
- */
+// Loads a FreeType face from memory, 'source' is only used for logging.
+FontFaceHandleFreetype LoadFace(const byte* data, int data_length, const String& source);
 
-namespace FreeType {
+// Releases the FreeType face.
+bool ReleaseFace(FontFaceHandleFreetype face, bool release_stream);
 
-class FontFamily : public Rml::Core::FontFamily
-{
-public:
-	FontFamily(const String& name);
-	~FontFamily();
+// Retrieves the font family, style and weight of the given font face.
+void GetFaceStyle(FontFaceHandleFreetype face, String& font_family, Style::FontStyle& style, Style::FontWeight& weight);
 
-	/// Adds a new face to the family.
-	/// @param[in] ft_face The previously loaded FreeType face.
-	/// @param[in] style The style of the new face.
-	/// @param[in] weight The weight of the new face.
-	/// @param[in] release_stream True if the application must free the face's memory stream.
-	/// @return True if the face was loaded successfully, false otherwise.
-	bool AddFace(void* ft_face, Style::FontStyle style, Style::FontWeight weight, bool release_stream) override;
-};
+// Initializes a face for a given font size. Glyphs are filled with the ASCII subset, and the font face metrics are set.
+bool InitialiseFaceHandle(FontFaceHandleFreetype face, int font_size, FontGlyphMap& glyphs, FontMetrics& metrics);
+
+// Build a new glyph representing the given code point and append to 'glyphs'.
+bool AppendGlyph(FontFaceHandleFreetype face, int font_size, Character character, FontGlyphMap& glyphs);
+
+// Returns the kerning between two characters.
+int GetKerning(FontFaceHandleFreetype face, int font_size, Character lhs, Character rhs);
 
 }
 }
 }
 
 #endif
-
-#endif

+ 2 - 6
Source/Core/BitmapFont/precompiled.h → Source/Core/FontEngineDefault/precompiled.h

@@ -26,13 +26,9 @@
  *
  */
 
-#ifndef RMLUICOREBITMAPFONTPRECOMPILED_H
-#define RMLUICOREBITMAPFONTPRECOMPILED_H
-
-#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT
+#ifndef RMLUICOREFONTENGINEDEFAULTPRECOMPILED_H
+#define RMLUICOREFONTENGINEDEFAULTPRECOMPILED_H
 
 #include "../precompiled.h"
 
 #endif
-
-#endif

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott