Pārlūkot izejas kodu

Updated graphics32

glscene 8 mēneši atpakaļ
vecāks
revīzija
cc9d88bd0f
100 mainītis faili ar 36214 papildinājumiem un 0 dzēšanām
  1. 744 0
      Externals/Graphics32/Examples/Blending/BlendVsMerge/BlendVsMerge.cbproj
  2. 33 0
      Externals/Graphics32/Examples/Blending/BlendVsMerge/BlendVsMerge.cpp
  3. 13 0
      Externals/Graphics32/Examples/Blending/BlendVsMerge/BlendVsMerge.dpr
  4. 173 0
      Externals/Graphics32/Examples/Blending/BlendVsMerge/BlendVsMerge.dproj
  5. 131 0
      Externals/Graphics32/Examples/Blending/BlendVsMerge/MainUnit.dfm
  6. 269 0
      Externals/Graphics32/Examples/Blending/BlendVsMerge/MainUnit.pas
  7. 3 0
      Externals/Graphics32/Examples/Blending/BlendVsMerge/Media.rc
  8. 65 0
      Externals/Graphics32/Examples/Blending/PixelCombine/MainUnit.dfm
  9. 292 0
      Externals/Graphics32/Examples/Blending/PixelCombine/MainUnit.pas
  10. 2 0
      Externals/Graphics32/Examples/Blending/PixelCombine/Media.rc
  11. 15 0
      Externals/Graphics32/Examples/Blending/PixelCombine/PixelCombine.dpr
  12. 167 0
      Externals/Graphics32/Examples/Blending/PixelCombine/PixelCombine.dproj
  13. 53 0
      Externals/Graphics32/Examples/Blending/PixelCombine/createbundle.sh
  14. 237 0
      Externals/Graphics32/Examples/Blending/TextureBlend/MainUnit.dfm
  15. 220 0
      Externals/Graphics32/Examples/Blending/TextureBlend/MainUnit.pas
  16. 3 0
      Externals/Graphics32/Examples/Blending/TextureBlend/Media.rc
  17. 13 0
      Externals/Graphics32/Examples/Blending/TextureBlend/TextureBlend.dpr
  18. 167 0
      Externals/Graphics32/Examples/Blending/TextureBlend/TextureBlend.dproj
  19. 53 0
      Externals/Graphics32/Examples/Blending/TextureBlend/createbundle.sh
  20. 13 0
      Externals/Graphics32/Examples/Drawing/AntiAliasing/AntiAliasing.dpr
  21. 167 0
      Externals/Graphics32/Examples/Drawing/AntiAliasing/AntiAliasing.dproj
  22. 25 0
      Externals/Graphics32/Examples/Drawing/AntiAliasing/MainUnit.dfm
  23. 260 0
      Externals/Graphics32/Examples/Drawing/AntiAliasing/MainUnit.pas
  24. 1 0
      Externals/Graphics32/Examples/Drawing/AntiAliasing/Media.rc
  25. 13 0
      Externals/Graphics32/Examples/Drawing/ArrowHead/ArrowHead.dpr
  26. 169 0
      Externals/Graphics32/Examples/Drawing/ArrowHead/ArrowHead.dproj
  27. 152 0
      Externals/Graphics32/Examples/Drawing/ArrowHead/MainUnit.dfm
  28. 523 0
      Externals/Graphics32/Examples/Drawing/ArrowHead/MainUnit.pas
  29. 3 0
      Externals/Graphics32/Examples/Drawing/ArrowHead/Media.rc
  30. 16 0
      Externals/Graphics32/Examples/Drawing/Benchmark/Benchmark.dpr
  31. 167 0
      Externals/Graphics32/Examples/Drawing/Benchmark/Benchmark.dproj
  32. 3565 0
      Externals/Graphics32/Examples/Drawing/Benchmark/Blend2D.Api.pas
  33. 17764 0
      Externals/Graphics32/Examples/Drawing/Benchmark/Blend2D.pas
  34. 18 0
      Externals/Graphics32/Examples/Drawing/Benchmark/DelphiBlend2D - License.txt
  35. 277 0
      Externals/Graphics32/Examples/Drawing/Benchmark/GR32_Polygons.Blend2D.pas
  36. 202 0
      Externals/Graphics32/Examples/Drawing/Benchmark/MainUnit.dfm
  37. 670 0
      Externals/Graphics32/Examples/Drawing/Benchmark/MainUnit.pas
  38. 1 0
      Externals/Graphics32/Examples/Drawing/Benchmark/Media.rc
  39. 16 0
      Externals/Graphics32/Examples/Drawing/Blurs/Blurs.dpr
  40. 170 0
      Externals/Graphics32/Examples/Drawing/Blurs/Blurs.dproj
  41. 309 0
      Externals/Graphics32/Examples/Drawing/Blurs/MainUnit.dfm
  42. 448 0
      Externals/Graphics32/Examples/Drawing/Blurs/MainUnit.pas
  43. 2 0
      Externals/Graphics32/Examples/Drawing/Blurs/Media.rc
  44. 13 0
      Externals/Graphics32/Examples/Drawing/Clipper/ClipperDemo.dpr
  45. 148 0
      Externals/Graphics32/Examples/Drawing/Clipper/ClipperDemo.dproj
  46. 116 0
      Externals/Graphics32/Examples/Drawing/Clipper/MainUnit.dfm
  47. 219 0
      Externals/Graphics32/Examples/Drawing/Clipper/MainUnit.pas
  48. 1 0
      Externals/Graphics32/Examples/Drawing/Clipper/Media.rc
  49. 14 0
      Externals/Graphics32/Examples/Drawing/CubicSpline/CubicSpline.dpr
  50. 167 0
      Externals/Graphics32/Examples/Drawing/CubicSpline/CubicSpline.dproj
  51. 32 0
      Externals/Graphics32/Examples/Drawing/CubicSpline/MainUnit.dfm
  52. 273 0
      Externals/Graphics32/Examples/Drawing/CubicSpline/MainUnit.pas
  53. 1 0
      Externals/Graphics32/Examples/Drawing/CubicSpline/Media.rc
  54. 13 0
      Externals/Graphics32/Examples/Drawing/Curves/Curves.dpr
  55. 167 0
      Externals/Graphics32/Examples/Drawing/Curves/Curves.dproj
  56. 49 0
      Externals/Graphics32/Examples/Drawing/Curves/MainUnit.dfm
  57. 390 0
      Externals/Graphics32/Examples/Drawing/Curves/MainUnit.pas
  58. 1 0
      Externals/Graphics32/Examples/Drawing/Curves/Media.rc
  59. 13 0
      Externals/Graphics32/Examples/Drawing/GammaBlur/GammaBlur.dpr
  60. 169 0
      Externals/Graphics32/Examples/Drawing/GammaBlur/GammaBlur.dproj
  61. 165 0
      Externals/Graphics32/Examples/Drawing/GammaBlur/MainUnit.dfm
  62. 207 0
      Externals/Graphics32/Examples/Drawing/GammaBlur/MainUnit.pas
  63. 3 0
      Externals/Graphics32/Examples/Drawing/GammaBlur/Media.rc
  64. 14 0
      Externals/Graphics32/Examples/Drawing/GammaCorrection/GammaCorrection.dpr
  65. 167 0
      Externals/Graphics32/Examples/Drawing/GammaCorrection/GammaCorrection.dproj
  66. 110 0
      Externals/Graphics32/Examples/Drawing/GammaCorrection/MainUnit.dfm
  67. 152 0
      Externals/Graphics32/Examples/Drawing/GammaCorrection/MainUnit.pas
  68. 1 0
      Externals/Graphics32/Examples/Drawing/GammaCorrection/Media.rc
  69. 13 0
      Externals/Graphics32/Examples/Drawing/GradFills/GradFills.dpr
  70. 147 0
      Externals/Graphics32/Examples/Drawing/GradFills/GradFills.dproj
  71. 285 0
      Externals/Graphics32/Examples/Drawing/GradFills/MainUnit.dfm
  72. 829 0
      Externals/Graphics32/Examples/Drawing/GradFills/MainUnit.pas
  73. 2 0
      Externals/Graphics32/Examples/Drawing/GradFills/Media.rc
  74. 744 0
      Externals/Graphics32/Examples/Drawing/GradLines/GradLines.cbproj
  75. 34 0
      Externals/Graphics32/Examples/Drawing/GradLines/GradLines.cpp
  76. 13 0
      Externals/Graphics32/Examples/Drawing/GradLines/GradLines.dpr
  77. 167 0
      Externals/Graphics32/Examples/Drawing/GradLines/GradLines.dproj
  78. 162 0
      Externals/Graphics32/Examples/Drawing/GradLines/MainUnit.dfm
  79. 155 0
      Externals/Graphics32/Examples/Drawing/GradLines/MainUnit.lfm
  80. 428 0
      Externals/Graphics32/Examples/Drawing/GradLines/MainUnit.pas
  81. 1 0
      Externals/Graphics32/Examples/Drawing/GradLines/Media.rc
  82. 53 0
      Externals/Graphics32/Examples/Drawing/GradLines/createbundle.sh
  83. 13 0
      Externals/Graphics32/Examples/Drawing/GradSampler/GradSampler.dpr
  84. 169 0
      Externals/Graphics32/Examples/Drawing/GradSampler/GradSampler.dproj
  85. 139 0
      Externals/Graphics32/Examples/Drawing/GradSampler/MainUnit.dfm
  86. 642 0
      Externals/Graphics32/Examples/Drawing/GradSampler/MainUnit.pas
  87. 1 0
      Externals/Graphics32/Examples/Drawing/GradSampler/Media.rc
  88. 17 0
      Externals/Graphics32/Examples/Drawing/Grow/Grow.dpr
  89. 149 0
      Externals/Graphics32/Examples/Drawing/Grow/Grow.dproj
  90. 277 0
      Externals/Graphics32/Examples/Drawing/Grow/MainUnit.dfm
  91. 348 0
      Externals/Graphics32/Examples/Drawing/Grow/MainUnit.pas
  92. 2 0
      Externals/Graphics32/Examples/Drawing/Grow/Media.rc
  93. 744 0
      Externals/Graphics32/Examples/Drawing/LineStippling/LineStippling.cbproj
  94. 34 0
      Externals/Graphics32/Examples/Drawing/LineStippling/LineStippling.cpp
  95. 15 0
      Externals/Graphics32/Examples/Drawing/LineStippling/LineStippling.dpr
  96. 167 0
      Externals/Graphics32/Examples/Drawing/LineStippling/LineStippling.dproj
  97. 51 0
      Externals/Graphics32/Examples/Drawing/LineStippling/MainUnit.dfm
  98. 150 0
      Externals/Graphics32/Examples/Drawing/LineStippling/MainUnit.pas
  99. 1 0
      Externals/Graphics32/Examples/Drawing/LineStippling/Media.rc
  100. 53 0
      Externals/Graphics32/Examples/Drawing/LineStippling/createbundle.sh

+ 744 - 0
Externals/Graphics32/Examples/Blending/BlendVsMerge/BlendVsMerge.cbproj

@@ -0,0 +1,744 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{35844EF1-92E1-454C-823C-6FDB54020649}</ProjectGuid>
+        <ProjectVersion>18.6</ProjectVersion>
+        <FrameworkType>VCL</FrameworkType>
+        <AppType>Application</AppType>
+        <MainSource>BlendVsMerge.cpp</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>3</TargetedPlatforms>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+        <DynamicRTL>true</DynamicRTL>
+        <UsePackages>true</UsePackages>
+        <IntermediateOutputDir>lib</IntermediateOutputDir>
+        <FinalOutputDir>bin</FinalOutputDir>
+        <BCC_wpar>false</BCC_wpar>
+        <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
+        <BCC_ExtendedErrorInfo>true</BCC_ExtendedErrorInfo>
+        <ILINK_TranslatedLibraryPath>$(BDSLIB)\$(PLATFORM)\release\$(LANGDIR);$(ILINK_TranslatedLibraryPath)</ILINK_TranslatedLibraryPath>
+        <ProjectType>CppVCLApplication</ProjectType>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
+        <AllPackageLibs>rtl.lib;vcl.lib;GR32_R.lib</AllPackageLibs>
+        <_TCHARMapping>wchar_t</_TCHARMapping>
+        <Multithreaded>true</Multithreaded>
+        <Icon_MainIcon>$(BDS)\bin\cbuilder_PROJECTICON.ico</Icon_MainIcon>
+        <UWP_CppLogo44>$(BDS)\bin\Artwork\Windows\UWP\cppreg_UwpDefault_44.png</UWP_CppLogo44>
+        <UWP_CppLogo150>$(BDS)\bin\Artwork\Windows\UWP\cppreg_UwpDefault_150.png</UWP_CppLogo150>
+        <IncludePath>$(IncludePath)</IncludePath>
+        <ILINK_LibraryPath>$(ILINK_LibraryPath)</ILINK_LibraryPath>
+        <SanitizedProjectName>BlendVsMerge</SanitizedProjectName>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <DCC_HppOutputARM>true</DCC_HppOutputARM>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <PackageImports>adortl;appanalytics;bcbie;bcbsmp;bindcomp;bindcompdbx;bindcompfmx;bindcompvcl;bindengine;CloudService;CustomIPTransport;DataSnapClient;DataSnapCommon;DataSnapConnectors;DatasnapConnectorsFreePascal;DataSnapFireDAC;DataSnapIndy10ServerTransport;DataSnapNativeClient;DataSnapProviderClient;DataSnapServer;DataSnapServerMidas;dbexpress;dbrtl;dbxcds;DbxClientDriver;DbxCommonDriver;DBXDb2Driver;DBXFirebirdDriver;DBXInformixDriver;DBXInterBaseDriver;DBXMSSQLDriver;DBXMySQLDriver;DBXOdbcDriver;DBXOracleDriver;DBXSqliteDriver;DBXSybaseASADriver;DBXSybaseASEDriver;dsnap;dsnapcon;dsnapxml;emsclient;emsclientfiredac;emsedge;emshosting;emsserverresource;FireDAC;FireDACADSDriver;FireDACASADriver;FireDACCommon;FireDACCommonDriver;FireDACCommonODBC;FireDACDb2Driver;FireDACDBXDriver;FireDACDSDriver;FireDACIBDriver;FireDACInfxDriver;FireDACMongoDBDriver;FireDACMSAccDriver;FireDACMSSQLDriver;FireDACMySQLDriver;FireDACODBCDriver;FireDACOracleDriver;FireDACPgDriver;FireDACSqliteDriver;FireDACTDataDriver;fmx;fmxase;fmxdae;fmxFireDAC;fmxobj;FMXTee;FmxTeeUI;GR32_D;GR32_R;IndyCore;IndyIPClient;IndyIPCommon;IndyIPServer;IndyProtocols;IndySystem;inet;inetdb;inetdbxpress;RESTBackendComponents;RESTComponents;rtl;soapmidas;soaprtl;soapserver;svn;SynEdit_BCB;Tee;TeeDB;TeeUI;tethering;vcl;vclactnband;vcldb;vcldsnap;vclFireDAC;vclie;vclimg;VCLRESTComponents;VclSmp;vcltouch;vclwinx;vclx;xmlrtl;$(PackageImports)</PackageImports>
+        <IncludePath>$(BDSINCLUDE)\windows\vcl;$(IncludePath)</IncludePath>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <PackageImports>adortl;appanalytics;bcbie;bcbsmp;bindcomp;bindcompdbx;bindcompfmx;bindcompvcl;bindengine;CloudService;CustomIPTransport;DataSnapClient;DataSnapCommon;DataSnapConnectors;DatasnapConnectorsFreePascal;DataSnapFireDAC;DataSnapIndy10ServerTransport;DataSnapNativeClient;DataSnapProviderClient;DataSnapServer;DataSnapServerMidas;dbexpress;dbrtl;dbxcds;DbxClientDriver;DbxCommonDriver;DBXDb2Driver;DBXFirebirdDriver;DBXInformixDriver;DBXInterBaseDriver;DBXMSSQLDriver;DBXMySQLDriver;DBXOdbcDriver;DBXOracleDriver;DBXSqliteDriver;DBXSybaseASADriver;DBXSybaseASEDriver;dsnap;dsnapcon;dsnapxml;emsclient;emsclientfiredac;emsedge;emshosting;emsserverresource;FireDAC;FireDACADSDriver;FireDACASADriver;FireDACCommon;FireDACCommonDriver;FireDACCommonODBC;FireDACDb2Driver;FireDACDBXDriver;FireDACDSDriver;FireDACIBDriver;FireDACInfxDriver;FireDACMongoDBDriver;FireDACMSAccDriver;FireDACMSSQLDriver;FireDACMySQLDriver;FireDACODBCDriver;FireDACOracleDriver;FireDACPgDriver;FireDACSqliteDriver;FireDACTDataDriver;fmx;fmxase;fmxdae;fmxFireDAC;fmxobj;FMXTee;FmxTeeUI;GR32_R;IndyCore;IndyIPClient;IndyIPCommon;IndyIPServer;IndyProtocols;IndySystem;inet;inetdb;inetdbxpress;RESTBackendComponents;RESTComponents;rtl;soapmidas;soaprtl;soapserver;Tee;TeeDB;TeeUI;tethering;vcl;vclactnband;vcldb;vcldsnap;vclFireDAC;vclie;vclimg;VCLRESTComponents;VclSmp;vcltouch;vclwinx;vclx;xmlrtl;$(PackageImports)</PackageImports>
+        <IncludePath>$(BDSINCLUDE)\windows\vcl;$(IncludePath)</IncludePath>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
+        <BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <Defines>_DEBUG;$(Defines)</Defines>
+        <BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
+        <BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
+        <DCC_Define>DEBUG</DCC_Define>
+        <BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
+        <TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
+        <BCC_StackFrames>true</BCC_StackFrames>
+        <ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
+        <TASM_Debugging>Full</TASM_Debugging>
+        <BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
+        <BCC_EnableCPPExceptions>true</BCC_EnableCPPExceptions>
+        <BCC_DisableFramePtrElimOpt>true</BCC_DisableFramePtrElimOpt>
+        <BCC_DisableSpellChecking>true</BCC_DisableSpellChecking>
+        <CLANG_UnwindTables>true</CLANG_UnwindTables>
+        <ILINK_LibraryPath>$(BDSLIB)\$(PLATFORM)\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+        <ILINK_TranslatedLibraryPath>$(BDSLIB)\$(PLATFORM)\debug\$(LANGDIR);$(ILINK_TranslatedLibraryPath)</ILINK_TranslatedLibraryPath>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+        <BCC_UseClassicCompiler>false</BCC_UseClassicCompiler>
+        <LinkPackageImports>rtl.bpi;vcl.bpi;GR32_R.bpi</LinkPackageImports>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+        <LinkPackageImports>rtl.bpi;vcl.bpi;GR32_R.bpi</LinkPackageImports>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <Defines>NDEBUG;$(Defines)</Defines>
+        <TASM_Debugging>None</TASM_Debugging>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+        <BCC_UseClassicCompiler>false</BCC_UseClassicCompiler>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+    </PropertyGroup>
+    <ItemGroup>
+        <CppCompile Include="BlendVsMerge.cpp">
+            <BuildOrder>0</BuildOrder>
+        </CppCompile>
+        <DelphiCompile Include="MainUnit.pas">
+            <BuildOrder>2</BuildOrder>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>CPlusPlusBuilder.Personality.12</Borland.Personality>
+        <Borland.ProjectType>CppVCLApplication</Borland.ProjectType>
+        <BorlandProject>
+            <CPlusPlusBuilder.Personality>
+                <ProjectProperties>
+                    <ProjectProperties Name="AutoShowDeps">False</ProjectProperties>
+                    <ProjectProperties Name="ManagePaths">True</ProjectProperties>
+                    <ProjectProperties Name="VerifyPackages">True</ProjectProperties>
+                    <ProjectProperties Name="IndexFiles">False</ProjectProperties>
+                </ProjectProperties>
+                <Source>
+                    <Source Name="MainSource">BlendVsMerge.cpp</Source>
+                </Source>
+                <Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcboffice2k260.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcbofficexp260.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
+                </Excluded_Packages>
+            </CPlusPlusBuilder.Personality>
+            <Deployment Version="3">
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\bin\cc32c260.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx32\libcgcrtl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx64\libcgstl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\bin\cc32260mt.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\bin\cc32260.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx32\libcgstl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(UsingDelphiRTL)'=='true'" LocalName="$(BDS)\bin\borlndmm.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(UsingDelphiRTL)'=='true'" LocalName="$(BDS)\bin64\borlndmm.dll" Class="DependencyModule">
+                    <Platform Name="Win64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\bin64\cc64260mt.dll" Class="DependencyModule">
+                    <Platform Name="Win64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="..\..\..\Binaries\Win32\Debug\BlendVsMerge.tds" Configuration="Debug" Class="DebugSymbols">
+                    <Platform Name="Win32">
+                        <RemoteName>BlendVsMerge.tds</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="..\..\..\Binaries\Win32\Debug\BlendVsMerge.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>BlendVsMerge.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\bin64\cc64260.dll" Class="DependencyModule">
+                    <Platform Name="Win64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\bin\cc32c260mt.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx64\libcgcrtl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1536">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2048">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch768">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_CppLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_CppLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Cpp.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Cpp.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

+ 33 - 0
Externals/Graphics32/Examples/Blending/BlendVsMerge/BlendVsMerge.cpp

@@ -0,0 +1,33 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USEFORMNS("MainUnit.pas", Mainunit, MainForm);
+//---------------------------------------------------------------------------
+int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
+{
+	try
+	{
+		Application->Initialize();
+		Application->MainFormOnTaskBar = true;
+		Application->CreateForm(__classid(TMainForm), &MainForm);
+		Application->Run();
+	}
+	catch (Exception &exception)
+	{
+		Application->ShowException(&exception);
+	}
+	catch (...)
+	{
+		try
+		{
+			throw Exception("");
+		}
+		catch (Exception &exception)
+		{
+			Application->ShowException(&exception);
+		}
+	}
+	return 0;
+}
+//---------------------------------------------------------------------------

+ 13 - 0
Externals/Graphics32/Examples/Blending/BlendVsMerge/BlendVsMerge.dpr

@@ -0,0 +1,13 @@
+program BlendVsMerge;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TMainForm, MainForm);
+  Application.Run;
+end.

+ 173 - 0
Externals/Graphics32/Examples/Blending/BlendVsMerge/BlendVsMerge.dproj

@@ -0,0 +1,173 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>BlendVsMerge.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{b302a43a-346a-4197-b1ff-98cc87430fff}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">BlendVsMerge</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>BlendVsMerge</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+        <AppDPIAwarenessMode>none</AppDPIAwarenessMode>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">BlendVsMerge.dpr</Source>
+                </Source>
+                <Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcboffice2k290.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcbofficexp290.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dcloffice2k290.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dclofficexp290.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
+                </Excluded_Packages>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 131 - 0
Externals/Graphics32/Examples/Blending/BlendVsMerge/MainUnit.dfm

@@ -0,0 +1,131 @@
+object MainForm: TMainForm
+  Left = 296
+  Top = 97
+  BorderIcons = [biSystemMenu, biMinimize]
+  BorderStyle = bsSingle
+  Caption = 'Blend vs. Merge Example'
+  ClientHeight = 456
+  ClientWidth = 272
+  Color = clBtnFace
+  ParentFont = True
+  Position = poScreenCenter
+  OnCreate = FormCreate
+  DesignSize = (
+    272
+    456)
+  TextHeight = 15
+  object LabelOverlay: TLabel
+    Left = 8
+    Top = 171
+    Width = 40
+    Height = 15
+    Anchors = [akLeft, akBottom]
+    Caption = 'Overlay'
+    Layout = tlCenter
+  end
+  object LabelBlendSettings: TLabel
+    Left = 8
+    Top = 84
+    Width = 75
+    Height = 15
+    Caption = 'Blend Settings'
+    Layout = tlCenter
+  end
+  object LabelVisible: TLabel
+    Left = 8
+    Top = 8
+    Width = 65
+    Height = 15
+    Caption = 'Visible Layer'
+    Layout = tlCenter
+  end
+  object LabelMergeHint: TLabel
+    Left = 71
+    Top = 106
+    Width = 190
+    Height = 31
+    AutoSize = False
+    Caption = 'Alpha values will be merged correctly.'
+    WordWrap = True
+  end
+  object LabelBlendHint: TLabel
+    Left = 71
+    Top = 138
+    Width = 190
+    Height = 29
+    AutoSize = False
+    Caption = 
+      'Alpha values of the background are assumed to be opaque -> faste' +
+      'r!'
+    WordWrap = True
+  end
+  object DstImg: TImage32
+    Left = 8
+    Top = 192
+    Width = 256
+    Height = 256
+    Anchors = [akLeft, akBottom]
+    Bitmap.DrawMode = dmBlend
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baCenter
+    Color = clBlack
+    ParentColor = False
+    Scale = 1.000000000000000000
+    ScaleMode = smNormal
+    TabOrder = 0
+    OnPaintStage = DstImgPaintStage
+  end
+  object RadioButtonBlend: TRadioButton
+    Left = 8
+    Top = 138
+    Width = 57
+    Height = 17
+    Caption = '&Blend'
+    TabOrder = 1
+    OnClick = RadioButtonBlendClick
+  end
+  object RadioButtonMerge: TRadioButton
+    Left = 8
+    Top = 105
+    Width = 57
+    Height = 17
+    Caption = '&Merge'
+    Checked = True
+    TabOrder = 2
+    TabStop = True
+    OnClick = RadioButtonMergeClick
+  end
+  object CheckBoxForeground: TCheckBox
+    Left = 8
+    Top = 52
+    Width = 81
+    Height = 17
+    Caption = '&Foreground'
+    Checked = True
+    State = cbChecked
+    TabOrder = 3
+    OnClick = CheckBoxImageClick
+  end
+  object CheckBoxBackground: TCheckBox
+    Left = 8
+    Top = 29
+    Width = 116
+    Height = 17
+    Caption = 'Back&ground  --->'
+    Checked = True
+    State = cbChecked
+    TabOrder = 4
+    OnClick = CheckBoxImageClick
+  end
+  object CheckBoxTransparent: TCheckBox
+    Left = 130
+    Top = 29
+    Width = 113
+    Height = 17
+    Caption = 'with transparency'
+    Checked = True
+    State = cbChecked
+    TabOrder = 5
+    OnClick = CheckBoxImageClick
+  end
+end

+ 269 - 0
Externals/Graphics32/Examples/Blending/BlendVsMerge/MainUnit.pas

@@ -0,0 +1,269 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is Texture Blend Example
+ *
+ * The Initial Developer(s) of the Original Code is:
+ * Christian-W. Budde <[email protected]>
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFDEF FPC}LCLIntf, LResources, Buttons, {$ENDIF}
+  SysUtils, Classes, Graphics, Controls, Forms, Math, StdCtrls, ExtCtrls,
+  GR32, GR32_Blend, GR32_Image;
+
+type
+  TMainForm = class(TForm)
+    CheckBoxBackground: TCheckBox;
+    CheckBoxForeground: TCheckBox;
+    CheckBoxTransparent: TCheckBox;
+    DstImg: TImage32;
+    LabelBlendHint: TLabel;
+    LabelBlendSettings: TLabel;
+    LabelMergeHint: TLabel;
+    LabelOverlay: TLabel;
+    LabelVisible: TLabel;
+    RadioButtonBlend: TRadioButton;
+    RadioButtonMerge: TRadioButton;
+    procedure FormCreate(Sender: TObject);
+    procedure CheckBoxImageClick(Sender: TObject);
+    procedure DstImgPaintStage(Sender: TObject; Buffer: TBitmap32;
+      StageNum: Cardinal);
+    procedure RadioButtonBlendClick(Sender: TObject);
+    procedure RadioButtonMergeClick(Sender: TObject);
+    procedure RadioButtonNoneClick(Sender: TObject);
+  private
+    FForeground: TBitmap32;
+    FBackground: TBitmap32;
+    FBackgroundOpaque: TBitmap32;
+    FBlendFunc: TBlendReg;
+    procedure ModifyAlphaValues;
+    procedure UpdateBlendModeEnabled;
+    procedure DrawBitmap;
+  end;
+
+var
+  MainForm: TMainForm;
+
+implementation
+
+{$R *.dfm}
+
+uses
+{$IFDEF Darwin}
+  MacOSAll,
+{$ENDIF}
+  GR32.ImageFormats.JPG,
+  GR32_Resamplers,
+  GR32_LowLevel;
+
+{ TMainForm }
+
+procedure TMainForm.FormCreate(Sender: TObject);
+begin
+  // setup custom checker board paint stage
+  with DstImg do
+  begin
+    with PaintStages[0]^ do //Set up custom paintstage to draw checkerboard
+    begin
+      Stage := PST_CUSTOM;
+      Parameter := 1; // use parameter to tag the stage, we inspect this in OnPaintStage
+    end;
+  end;
+
+  // Load the textures (note size 256x256 is implicity expected!)
+  FForeground := TBitmap32.Create;
+  FForeground.LoadFromResourceName(HInstance, 'TextureA', 'JPG');
+
+  FBackground := TBitmap32.Create;
+  FBackground.LoadFromResourceName(HInstance, 'TextureB', 'JPG');
+
+  // clone background (= store original background without transparency)
+  FBackgroundOpaque := TBitmap32.Create;
+  FBackgroundOpaque.Assign(FBackground);
+
+  // apply transparency to both background and foreground
+  ModifyAlphaValues;
+
+  DstImg.Bitmap.SetSize(FForeground.Width, FForeground.Height);
+  FBlendFunc := MergeReg;
+  DrawBitmap;
+end;
+
+procedure TMainForm.ModifyAlphaValues;
+var
+  X, Y: Integer;
+  Line: PColor32EntryArray;
+begin
+  // apply a linear alpha gradient from left (transparent) to right (opaque)
+  for Y := 0 to FForeground.Height - 1 do
+  begin
+    Line := PColor32EntryArray(FForeground.ScanLine[Y]);
+    for X := 0 to FForeground.Width - 1 do
+      Line^[X].A := X;
+  end;
+
+  // apply a linear alpha gradient from top (transparent) to bottom (opaque)
+  for Y := 0 to FBackground.Height - 1 do
+  begin
+    Line := PColor32EntryArray(FBackground.ScanLine[Y]);
+    for X := 0 to FBackground.Width - 1 do
+      Line^[X].A := Y;
+  end;
+end;
+
+procedure TMainForm.DstImgPaintStage(Sender: TObject; Buffer: TBitmap32;
+  StageNum: Cardinal);
+const
+  Colors: array [Boolean] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
+var
+  R: TRect;
+  I, J: Integer;
+  OddY: Integer;
+  TilesHorz, TilesVert: Integer;
+  TileX, TileY: Integer;
+  TileHeight, TileWidth: Integer;
+begin
+  // draw checker board
+  with TImgView32(Sender) do
+  begin
+    BeginUpdate;
+    R := GetViewportRect;
+    TileHeight := 8;
+    TileWidth := 8;
+    TilesHorz := (R.Right - R.Left) div TileWidth;
+    TilesVert := (R.Bottom - R.Top) div TileHeight;
+    TileY := 0;
+    for J := 0 to TilesVert do
+    begin
+      TileX := 0;
+      OddY := J and $1;
+      for I := 0 to TilesHorz do
+      begin
+        Buffer.FillRectS(TileX, TileY, TileX + TileWidth, TileY +
+          TileHeight, Colors[I and $1 = OddY]);
+        Inc(TileX, TileWidth);
+      end;
+      Inc(TileY, TileHeight);
+    end;
+    EndUpdate;
+  end;
+end;
+
+procedure TMainForm.RadioButtonNoneClick(Sender: TObject);
+begin
+  DstImg.Bitmap.Clear(0);
+
+  // Needed under Mac OS X
+  DstImg.Invalidate;
+end;
+
+procedure TMainForm.RadioButtonBlendClick(Sender: TObject);
+begin
+  FBlendFunc := BlendReg;
+
+  DrawBitmap;
+end;
+
+procedure TMainForm.RadioButtonMergeClick(Sender: TObject);
+begin
+  FBlendFunc := MergeReg;
+
+  DrawBitmap;
+end;
+
+procedure TMainForm.CheckBoxImageClick(Sender: TObject);
+begin
+  DrawBitmap;
+  UpdateBlendModeEnabled;
+end;
+
+procedure TMainForm.UpdateBlendModeEnabled;
+var
+  Value: Boolean;
+begin
+  Value := CheckBoxForeground.Checked and CheckBoxBackground.Checked;
+  RadioButtonBlend.Enabled := Value;
+  RadioButtonMerge.Enabled := Value;
+end;
+
+procedure TMainForm.DrawBitmap;
+var
+  X, Y: Integer;
+  PSrcF, PSrcB, PDst: PColor32Array;
+  Background: TBitmap32;
+begin
+  // select whether the opaque or transparent image shall be used
+  if CheckBoxTransparent.Checked then
+    Background := FBackground
+  else
+    Background := FBackgroundOpaque;
+
+  if CheckBoxForeground.Checked then
+  begin
+    if CheckBoxBackground.Checked then
+      for Y := 0 to FForeground.Height - 1 do
+      begin
+        // blend lines according to the blend function (blend or merge)
+        PSrcF := PColor32Array(FForeground.ScanLine[Y]);
+        PSrcB := PColor32Array(Background.ScanLine[Y]);
+        PDst := PColor32Array(DstImg.Bitmap.ScanLine[Y]);
+        for X := 0 to FForeground.Width - 1 do
+          PDst[X] := FBlendFunc(PSrcF[X], PSrcB[X]);
+      end
+    else
+      for Y := 0 to FForeground.Height - 1 do
+      begin
+        // copy lines from the foreground image
+        PSrcF := PColor32Array(FForeground.ScanLine[Y]);
+        PDst := PColor32Array(DstImg.Bitmap.ScanLine[Y]);
+        MoveLongword(PSrcF^, PDst^, FForeground.Width);
+      end
+  end
+  else
+  begin
+    if CheckBoxBackground.Checked then
+      for Y := 0 to FForeground.Height - 1 do
+      begin
+        // copy lines from the background image
+        PSrcB := PColor32Array(Background.ScanLine[Y]);
+        PDst := PColor32Array(DstImg.Bitmap.ScanLine[Y]);
+        MoveLongword(PSrcB^, PDst^, FForeground.Width);
+      end
+    else
+      DstImg.Bitmap.Clear(0);
+  end;
+
+  // Needed under Mac OS X
+  DstImg.Invalidate;
+end;
+
+end.

+ 3 - 0
Externals/Graphics32/Examples/Blending/BlendVsMerge/Media.rc

@@ -0,0 +1,3 @@
+MainIcon ICON "../../Media/GR32.ico"
+TextureA JPG "../../Media/texture_a.jpg"
+TextureB JPG "../../Media/texture_b.jpg"

+ 65 - 0
Externals/Graphics32/Examples/Blending/PixelCombine/MainUnit.dfm

@@ -0,0 +1,65 @@
+object FormPixelCombine: TFormPixelCombine
+  Left = 295
+  Top = 110
+  Caption = 'PixelCombine Example'
+  ClientHeight = 346
+  ClientWidth = 564
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCreate = FormCreate
+  DesignSize = (
+    564
+    346)
+  PixelsPerInch = 96
+  TextHeight = 13
+  object ImgView: TImgView32
+    Left = 16
+    Top = 20
+    Width = 393
+    Height = 309
+    Anchors = [akLeft, akTop, akRight, akBottom]
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baCustom
+    Color = clBtnShadow
+    ParentColor = False
+    Scale = 1.000000000000000000
+    ScaleMode = smScale
+    ScrollBars.ShowHandleGrip = True
+    ScrollBars.Style = rbsDefault
+    ScrollBars.Size = 16
+    OverSize = 0
+    TabOrder = 0
+  end
+  object RadioGroup: TRadioGroup
+    Left = 415
+    Top = 20
+    Width = 141
+    Height = 285
+    Anchors = [akTop, akRight]
+    Caption = 'Operation'
+    ItemIndex = 0
+    Items.Strings = (
+      'Opaque (none)'
+      'Add / Plus / Lighter'
+      'Sub'
+      'Modulate / Multiply'
+      'Min / Darken'
+      'Max / Lighten'
+      'Screen'
+      'Color-Dodge'
+      'Color-Burn'
+      'Difference'
+      'Exclusion'
+      'Pattern'
+      'Blend'
+      'Blend Add'
+      'Blend Modulate')
+    TabOrder = 1
+    OnClick = RadioGroupClick
+  end
+end

+ 292 - 0
Externals/Graphics32/Examples/Blending/PixelCombine/MainUnit.pas

@@ -0,0 +1,292 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is PixelCombine Example
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFNDEF FPC} Windows, {$ELSE} LCLIntf, LCLType, LResources, {$ENDIF}
+  SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
+  GR32,
+  GR32_Image,
+  GR32_Layers;
+
+type
+  TFormPixelCombine = class(TForm)
+    ImgView: TImgView32;
+    RadioGroup: TRadioGroup;
+    procedure FormCreate(Sender: TObject);
+    procedure RadioGroupClick(Sender: TObject);
+  protected
+    procedure PC_Add(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_Sub(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_Modulate(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_Min(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_Max(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_Screen(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_ColorBurn(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_ColorDodge(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_Difference(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_Exclusion(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_Pattern(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_Blend(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_BlendAdd(F: TColor32; var B: TColor32; M: Cardinal);
+    procedure PC_BlendModulate(F: TColor32; var B: TColor32; M: Cardinal);
+  private
+    FPatCount: Integer;
+    FLayer1: TBitmapLayer;
+    FLayer2: TBitmapLayer;
+  end;
+
+var
+  FormPixelCombine: TFormPixelCombine;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Types,
+  GR32_Blend,
+  GR32_RangeBars,
+  GR32.ImageFormats.JPG;
+
+{ TFormPixelCombine }
+
+procedure TFormPixelCombine.FormCreate(Sender: TObject);
+
+  procedure GenerateBitmap(Bitmap: TBitmap32);
+  var
+    X, Y: Integer;
+    SinY, SinX: Double;
+    Color: TColor32;
+  begin
+    // Just a pattern with some variation
+    for Y := 0 to Bitmap.Height-1 do
+    begin
+      SinY := Sin(Y * 0.1);
+
+      for X := 0 to Bitmap.Width-1 do
+      begin
+        SinX := Sin(X * 0.1);
+
+        Color :=  Gray32(Round(((SinX + SinY) * 0.25 + 0.5) * 255));
+        // Alpha gradient
+        Color := SetAlpha(Color, MulDiv(255, Y, Bitmap.Height-1));
+        
+        Bitmap[X, Y] := Color;    
+      end;
+    end;
+  end;
+
+var
+  RubberbandLayer: TRubberbandLayer;
+  r: TRect;
+  Viewport: TRect;
+  Location: TFloatRect;
+const
+  BitmapSize = 200;
+  BitmapOffset = 20;
+begin
+  // Load background picture 'Runner'
+  ImgView.Bitmap.LoadFromResourceName(HInstance, 'Runner', RT_RCDATA);
+
+  // Create foreground bitmap layers
+  
+  // First layer is unscaled
+  FLayer1 := TBitmapLayer.Create(ImgView.Layers);
+  FLayer1.Visible := False;
+  FLayer1.Bitmap.SetSize(BitmapSize, BitmapSize);
+  FLayer1.Bitmap.DrawMode := dmCustom;
+  GenerateBitmap(FLayer1.Bitmap);
+  FLayer1.Scaled := False;
+  // Position top-left
+  r := FLayer1.Bitmap.BoundsRect;
+  r.Offset(BitmapOffset, BitmapOffset);
+  if (FLayer1.Scaled) then
+    // Location is relative to bitmap
+    Location := ImgView.ControlToBitmap(r)
+  else
+    // Location is relative to viewport
+    Location := FloatRect(r);
+  FLayer1.Location := Location;
+
+  // Second layer is scaled
+  FLayer2 := TBitmapLayer.Create(ImgView.Layers);
+  FLayer2.Visible := False;
+  FLayer2.Bitmap.Assign(FLayer1.Bitmap);
+  FLayer2.Scaled := True;
+  // Position bottom-right
+  r := FLayer1.Bitmap.BoundsRect;
+  Viewport := ImgView.GetViewportRect;
+  r.Offset(Viewport.Width-r.Width-BitmapOffset, Viewport.Height-r.Height-BitmapOffset);
+  if (FLayer2.Scaled) then
+    // Location is relative to bitmap
+    Location := ImgView.ControlToBitmap(r)
+  else
+    // Location is relative to viewport
+    Location := FloatRect(r);
+  FLayer2.Location := Location;
+
+
+  // Create rubberband layers so we can move the foreground layers around
+  RubberbandLayer := TRubberbandLayer.Create(ImgView.Layers);
+  RubberbandLayer.Visible := False;
+  RubberbandLayer.ChildLayer := FLayer1;
+  RubberbandLayer.Handles := [rhCenter, rhFrame, rhCorners];
+  RubberbandLayer.ChildLayer.Visible := True;
+  RubberbandLayer.Visible := True;
+
+  RubberbandLayer := TRubberbandLayer.Create(ImgView.Layers);
+  RubberbandLayer.Visible := False;
+  RubberbandLayer.ChildLayer := FLayer2;
+  RubberbandLayer.Handles := [rhCenter, rhFrame, rhCorners];
+  RubberbandLayer.ChildLayer.Visible := True;
+  RubberbandLayer.Visible := True;
+end;
+
+procedure TFormPixelCombine.PC_Add(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorAdd(F, B);
+end;
+
+procedure TFormPixelCombine.PC_Max(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorMax(F, B);
+end;
+
+procedure TFormPixelCombine.PC_Min(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorMin(F, B);
+end;
+
+procedure TFormPixelCombine.PC_Modulate(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorModulate(F, B);
+end;
+
+procedure TFormPixelCombine.PC_Pattern(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  FPatCount := 1 - FPatCount;
+  if FPatCount = 0 then
+    B := F;
+end;
+
+procedure TFormPixelCombine.PC_Sub(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorSub(F, B);
+end;
+
+procedure TFormPixelCombine.PC_Screen(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorScreen(F, B);
+end;
+
+procedure TFormPixelCombine.PC_ColorDodge(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorDodge(F, B);
+end;
+
+procedure TFormPixelCombine.PC_ColorBurn(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorBurn(F, B);
+end;
+
+procedure TFormPixelCombine.PC_Difference(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorDifference(F, B);
+end;
+
+procedure TFormPixelCombine.PC_Exclusion(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := ColorExclusion(F, B);
+end;
+
+procedure TFormPixelCombine.PC_Blend(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := BlendReg(F, B);
+end;
+
+procedure TFormPixelCombine.PC_BlendAdd(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := BlendColorAdd(F, B);
+end;
+
+procedure TFormPixelCombine.PC_BlendModulate(F: TColor32; var B: TColor32; M: Cardinal);
+begin
+  B := BlendColorModulate(F, B);
+end;
+
+procedure TFormPixelCombine.RadioGroupClick(Sender: TObject);
+begin
+  case RadioGroup.ItemIndex of
+    0:
+      FLayer1.Bitmap.OnPixelCombine := nil;
+    1:
+      FLayer1.Bitmap.OnPixelCombine := PC_Add;
+    2:
+      FLayer1.Bitmap.OnPixelCombine := PC_Sub;
+    3:
+      FLayer1.Bitmap.OnPixelCombine := PC_Modulate;
+    4:
+      FLayer1.Bitmap.OnPixelCombine := PC_Min;
+    5:
+      FLayer1.Bitmap.OnPixelCombine := PC_Max;
+    6:
+      FLayer1.Bitmap.OnPixelCombine := PC_Screen;
+    7:
+      FLayer1.Bitmap.OnPixelCombine := PC_ColorDodge;
+    8:
+      FLayer1.Bitmap.OnPixelCombine := PC_ColorBurn;
+    9:
+      FLayer1.Bitmap.OnPixelCombine := PC_Difference;
+    10:
+      FLayer1.Bitmap.OnPixelCombine := PC_Exclusion;
+    11:
+      FLayer1.Bitmap.OnPixelCombine := PC_Pattern;
+    12:
+      FLayer1.Bitmap.OnPixelCombine := PC_Blend;
+    13:
+      FLayer1.Bitmap.OnPixelCombine := PC_BlendAdd;
+    14:
+      FLayer1.Bitmap.OnPixelCombine := PC_BlendModulate;
+  end;
+  FLayer2.Bitmap.OnPixelCombine := FLayer1.Bitmap.OnPixelCombine;
+  
+  FLayer1.Changed;
+  FLayer2.Changed;
+end;
+
+end.

+ 2 - 0
Externals/Graphics32/Examples/Blending/PixelCombine/Media.rc

@@ -0,0 +1,2 @@
+MainIcon ICON "../../Media/GR32.ico"
+Runner RCDATA "../../Media/runner.jpg"

+ 15 - 0
Externals/Graphics32/Examples/Blending/PixelCombine/PixelCombine.dpr

@@ -0,0 +1,15 @@
+program PixelCombine;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+{$R '..\manifest.res'}
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFormPixelCombine, FormPixelCombine);
+  Application.Run;
+end.

+ 167 - 0
Externals/Graphics32/Examples/Blending/PixelCombine/PixelCombine.dproj

@@ -0,0 +1,167 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>PixelCombine.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{d7da5c8a-84db-4ecc-9fa1-232d5ec95513}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">PixelCombine</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>PixelCombine</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">PixelCombine.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 53 - 0
Externals/Graphics32/Examples/Blending/PixelCombine/createbundle.sh

@@ -0,0 +1,53 @@
+#!/bin/sh
+# Force Bourne shell in case tcsh is default.
+#
+appname=PixelCombine
+appfolder=$appname.app
+macosfolder=$appfolder/Contents/MacOS
+plistfile=$appfolder/Contents/Info.plist
+appfile=$appname
+#
+if ! [ -e $appfile ]
+then
+  echo "$appfile does not exist"
+elif [ -e $appfolder ]
+then
+  echo "$appfolder already exists"
+else
+  echo "Creating $appfolder..."
+  mkdir $appfolder
+  mkdir $appfolder/Contents
+  mkdir $appfolder/Contents/MacOS
+  mkdir $appfolder/Contents/Resources
+#
+# Instead of copying executable into .app folder after each compile,
+# simply create a symbolic link to executable.
+  ln -s ../../../$appname $macosfolder/$appname
+# Also create a symbolic link for the resource files
+  ln -s ../../../../../../Media $appfolder/Contents/Resources/Media
+#
+# Create PkgInfo file.
+  echo "APPL????" >$appfolder/Contents/PkgInfo
+#
+# Create information property list file (Info.plist).
+  echo '<?xml version="1.0" encoding="UTF-8"?>' >$plistfile
+  echo '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >>$plistfile
+  echo '<plist version="1.0">' >>$plistfile
+  echo '<dict>' >>$plistfile
+  echo '  <key>CFBundleDevelopmentRegion</key>' >>$plistfile
+  echo '  <string>English</string>' >>$plistfile
+  echo '  <key>CFBundleExecutable</key>' >>$plistfile
+  echo '  <string>'$appname'</string>' >>$plistfile
+  echo '  <key>CFBundleInfoDictionaryVersion</key>' >>$plistfile
+  echo '  <string>6.0</string>' >>$plistfile
+  echo '  <key>CFBundlePackageType</key>' >>$plistfile
+  echo '  <string>APPL</string>' >>$plistfile
+  echo '  <key>CFBundleSignature</key>' >>$plistfile
+  echo '  <string>????</string>' >>$plistfile
+  echo '  <key>CFBundleVersion</key>' >>$plistfile
+  echo '  <string>1.0</string>' >>$plistfile
+  echo '  <key>CSResourcesFileMapped</key>' >>$plistfile
+  echo '  <true/>' >>$plistfile
+  echo '</dict>' >>$plistfile
+  echo '</plist>' >>$plistfile
+fi

+ 237 - 0
Externals/Graphics32/Examples/Blending/TextureBlend/MainUnit.dfm

@@ -0,0 +1,237 @@
+object MainForm: TMainForm
+  Left = 296
+  Top = 97
+  BorderIcons = [biSystemMenu, biMinimize]
+  BorderStyle = bsSingle
+  Caption = 'Texture Blend Example'
+  ClientHeight = 665
+  ClientWidth = 537
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poScreenCenter
+  OnCreate = FormCreate
+  PixelsPerInch = 96
+  TextHeight = 13
+  object LabelMasterAlpha: TLabel
+    Left = 272
+    Top = 32
+    Width = 59
+    Height = 13
+    Caption = 'MasterAlpha'
+  end
+  object LabelCombinedTexture: TLabel
+    Left = 272
+    Top = 88
+    Width = 258
+    Height = 17
+    Alignment = taCenter
+    AutoSize = False
+    Caption = 'Combined Texture'
+    Color = clAppWorkSpace
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWhite
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentColor = False
+    ParentFont = False
+    Layout = tlCenter
+  end
+  object LabelWeightmap: TLabel
+    Left = 8
+    Top = 88
+    Width = 258
+    Height = 17
+    Alignment = taCenter
+    AutoSize = False
+    Caption = 'Weightmap'
+    Color = clAppWorkSpace
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWhite
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentColor = False
+    ParentFont = False
+    Layout = tlCenter
+  end
+  object LabelTextureA: TLabel
+    Left = 8
+    Top = 376
+    Width = 258
+    Height = 17
+    Alignment = taCenter
+    AutoSize = False
+    Caption = 'Texture A'
+    Color = clAppWorkSpace
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWhite
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentColor = False
+    ParentFont = False
+    Layout = tlCenter
+  end
+  object LabelTextureB: TLabel
+    Left = 272
+    Top = 376
+    Width = 258
+    Height = 17
+    Alignment = taCenter
+    AutoSize = False
+    Caption = 'Texture B'
+    Color = clAppWorkSpace
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWhite
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentColor = False
+    ParentFont = False
+    Layout = tlCenter
+  end
+  object LabelBlendSettings: TLabel
+    Left = 272
+    Top = 8
+    Width = 258
+    Height = 17
+    AutoSize = False
+    Caption = ' Blend Settings'
+    Color = clAppWorkSpace
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWhite
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentColor = False
+    ParentFont = False
+    Layout = tlCenter
+  end
+  object LabelBlendmode: TLabel
+    Left = 272
+    Top = 59
+    Width = 53
+    Height = 13
+    Caption = 'Blendmode'
+  end
+  object LabelWeightmapSettings: TLabel
+    Left = 8
+    Top = 8
+    Width = 258
+    Height = 17
+    AutoSize = False
+    Caption = ' Weightmap Settings'
+    Color = clAppWorkSpace
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWhite
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentColor = False
+    ParentFont = False
+    Layout = tlCenter
+  end
+  object MasterAlphaBar: TGaugeBar
+    Left = 336
+    Top = 32
+    Width = 193
+    Height = 16
+    Backgnd = bgPattern
+    Max = 255
+    ShowArrows = False
+    ShowHandleGrip = True
+    Style = rbsMac
+    Position = 200
+    OnChange = MasterAlphaBarChange
+  end
+  object BlendBox: TComboBox
+    Left = 336
+    Top = 56
+    Width = 193
+    Height = 21
+    Style = csDropDownList
+    TabOrder = 1
+    OnChange = MasterAlphaBarChange
+    Items.Strings = (
+      'Normal'
+      'Soft Masked'
+      'Color Add'
+      'Color Sub'
+      'Color Div'
+      'Color Modulate'
+      'Color Max'
+      'Color Min'
+      'Color Difference'
+      'Color Average'
+      'Color Exclusion'
+      'Color Screen'
+      'Color Dodge'
+      'Color Burn')
+  end
+  object CombImg: TImage32
+    Left = 272
+    Top = 112
+    Width = 258
+    Height = 258
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baCenter
+    Color = clBlack
+    ParentColor = False
+    Scale = 1.000000000000000000
+    ScaleMode = smNormal
+    TabOrder = 2
+  end
+  object WeightmapImg: TImage32
+    Left = 8
+    Top = 112
+    Width = 258
+    Height = 258
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baCenter
+    Color = clBlack
+    ParentColor = False
+    Scale = 1.000000000000000000
+    ScaleMode = smNormal
+    TabOrder = 3
+  end
+  object TexAImg: TImage32
+    Left = 8
+    Top = 400
+    Width = 258
+    Height = 258
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baCenter
+    Color = clBlack
+    ParentColor = False
+    Scale = 1.000000000000000000
+    ScaleMode = smNormal
+    TabOrder = 4
+  end
+  object TexBImg: TImage32
+    Left = 272
+    Top = 400
+    Width = 258
+    Height = 258
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baCenter
+    Color = clBlack
+    ParentColor = False
+    Scale = 1.000000000000000000
+    ScaleMode = smNormal
+    TabOrder = 5
+  end
+  object GenerateButton: TButton
+    Left = 8
+    Top = 32
+    Width = 257
+    Height = 25
+    Caption = 'Generate Random Weightmap'
+    TabOrder = 6
+  end
+end

+ 220 - 0
Externals/Graphics32/Examples/Blending/TextureBlend/MainUnit.pas

@@ -0,0 +1,220 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is Texture Blend Example
+ *
+ * The Initial Developer(s) of the Original Code is:
+ * Michael Hansen <[email protected]>
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFNDEF FPC} Windows, {$ELSE} LCLIntf, LResources, LCLType, Buttons, {$ENDIF}
+  SysUtils, Classes, Graphics, Controls, Forms, Math, StdCtrls, ExtCtrls,
+  GR32_Image, GR32_RangeBars;
+
+type
+  TMainForm = class(TForm)
+    BlendBox: TComboBox;
+    CombImg: TImage32;
+    GenerateButton: TButton;
+    LabelBlendmode: TLabel;
+    LabelBlendSettings: TLabel;
+    LabelCombinedTexture: TLabel;
+    LabelMasterAlpha: TLabel;
+    LabelTextureA: TLabel;
+    LabelTextureB: TLabel;
+    LabelWeightmap: TLabel;
+    LabelWeightmapSettings: TLabel;
+    MasterAlphaBar: TGaugeBar;
+    TexAImg: TImage32;
+    TexBImg: TImage32;
+    WeightmapImg: TImage32;
+    procedure FormCreate(Sender: TObject);
+    procedure MasterAlphaBarChange(Sender: TObject);
+  public
+    procedure GenerateWeightmap(Sender: TObject);
+  end;
+
+var
+  MainForm: TMainForm;
+
+implementation
+
+{$R *.dfm}
+
+uses
+{$IFDEF Darwin}
+  MacOSAll,
+{$ENDIF}
+  GR32,
+  GR32_Resamplers,
+  GR32_LowLevel,
+  GR32_Blend,
+  GR32.ImageFormats.JPG;
+
+var
+  ColorAlgebraReg: TBlendReg;
+
+function ColorAlgebraEx(F, B: TColor32; M: Cardinal): TColor32;
+begin
+  // Call the coloralgebra routine in action, restore foreground alpha and blend
+  Result := BlendRegEx(ColorAlgebraReg(F, B) and $FFFFFF or F and $FF000000, B, M);
+end;
+
+function SoftMaskedEx(F, B: TColor32; M: Cardinal): TColor32;
+var
+   X: Integer;
+begin
+  // Some sort of masking with MasterAlpha (as threshold) included
+  X := F shr 24 - (255 - M);
+  if X > 0 then
+    Result := F
+  else
+  if X = 0 then
+    Result := ColorAverage(F, B) // Create soft edges
+  else
+    Result := B;
+end;
+
+{ TMainForm }
+
+procedure TMainForm.FormCreate(Sender: TObject);
+begin
+  // Load the textures (note size 256x256 is implicity expected!)
+  TexAImg.Bitmap.LoadFromResourceName(HInstance, 'TextureA', RT_RCDATA);
+  TexBImg.Bitmap.LoadFromResourceName(HInstance, 'TextureB', RT_RCDATA);
+
+  BlendBox.ItemIndex := 0;
+
+  CombImg.Bitmap.SetSizeFrom(TexBImg.Bitmap);
+
+  // Set up Weightmap and trigger generate
+  WeightmapImg.Bitmap.SetSize(256, 256);
+  GenerateButton.OnClick := GenerateWeightmap;
+
+  //we don't want the same series of weightmaps repeat every time the app is run
+  Randomize;
+
+  GenerateWeightmap(Self);
+end;
+
+procedure TMainForm.GenerateWeightmap(Sender: TObject);
+// Below code is very much based on experimentation, feel free to play around..
+var
+  a, b, c: Single;
+
+  function GenerateSomething(x, y : Single): Single;
+  begin
+    if a < 0.6 then
+      Result := Max(Cos(x * PI * a * 2 + b), Sqr(0.1 + c + x*y - y)) *
+        (Sin(y * b * a) - c + ArcTan2(x + Cos((x - y) * b), y + a))
+    else
+      Result := Cos(x * PI * a * 2 + c) * Sin(y * b * a) +
+        Sin(ArcTan2(x + Cos((x - y) * b), y * c * Sin(x - a)));
+  end;
+
+const
+  nS = 1 / 255;
+
+var
+  I, J: Integer;
+  W : TColor32;
+  D, WImg: PColor32;
+  x, y: Single;
+begin
+  // Setup some random factors:
+  a := 0.01 + Random;
+  b := PI * 10 * a * (Random * Random * 2 - 1);
+  c := Random - Random;
+
+  // We use the weightmap as TexB alpha, so we write that on the loop too
+  D := @TexBImg.Bitmap.Bits[0];
+  WImg := @WeightmapImg.Bitmap.Bits[0];
+  for J := 0 to 255 do
+    for I := 0 to 255 do
+    begin
+      x := Cos(I * nS + (PI * a));
+      y := Sin(J * nS * (PI * c));
+      W := Round(Constrain(Abs(Min(GenerateSomething(x * c, y),
+        GenerateSomething(y + c , x * a))) * 200, 0, 255));
+      if c > 0 then
+        WImg^ := ColorDifference(WImg^, $FF000000 + W shl 16 + W shl 8 + W)
+      else
+        WImg^ := $FF000000 + W shl 16 + W shl 8 + W;
+
+      D^ := D^ and $00FFFFFF or W shl 24;
+      Inc(D);
+      Inc(WImg);
+    end;
+
+  WeightmapImg.Invalidate;
+  MasterAlphaBarChange(Self);
+end;
+
+procedure TMainForm.MasterAlphaBarChange(Sender: TObject);
+var
+  ABlendRegEx: TBlendRegEx;
+begin
+  // Setup blendmode
+  case BlendBox.ItemIndex of
+    0: ABlendRegEx := BlendRegEx;
+    1: ABlendRegEx := SoftMaskedEx;
+  else
+    begin
+       ABlendRegEx := ColorAlgebraEx;
+       case BlendBox.ItemIndex of
+         2: ColorAlgebraReg := ColorAdd;
+         3: ColorAlgebraReg := ColorSub;
+         4: ColorAlgebraReg := ColorDiv;
+         5: ColorAlgebraReg := ColorModulate;
+         6: ColorAlgebraReg := ColorMax;
+         7: ColorAlgebraReg := ColorMin;
+         8: ColorAlgebraReg := ColorDifference;
+         9: ColorAlgebraReg := ColorAverage;
+         10: ColorAlgebraReg := ColorExclusion;
+         11: ColorAlgebraReg := ColorScreen;
+         12: ColorAlgebraReg := ColorScreen;
+         13: ColorAlgebraReg := ColorDodge;
+         14: ColorAlgebraReg := ColorBurn;
+       end;
+    end;
+ end;
+
+  // Combine Texture A with B
+  BlendTransfer(CombImg.Bitmap, 0, 0, CombImg.Bitmap.BoundsRect, TexBImg.Bitmap,
+    TexBImg.Bitmap.BoundsRect, TexAImg.Bitmap, TexAImg.Bitmap.BoundsRect,
+    ABlendRegEx, MasterAlphaBar.Position);
+
+  // Needed under Mac OS X
+  CombImg.Invalidate;
+end;
+
+end.

+ 3 - 0
Externals/Graphics32/Examples/Blending/TextureBlend/Media.rc

@@ -0,0 +1,3 @@
+MainIcon ICON "../../Media/GR32.ico"
+TextureA RCDATA "../../Media/texture_a.jpg"
+TextureB RCDATA "../../Media/texture_b.jpg"

+ 13 - 0
Externals/Graphics32/Examples/Blending/TextureBlend/TextureBlend.dpr

@@ -0,0 +1,13 @@
+program TextureBlend;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TMainForm, MainForm);
+  Application.Run;
+end.

+ 167 - 0
Externals/Graphics32/Examples/Blending/TextureBlend/TextureBlend.dproj

@@ -0,0 +1,167 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>TextureBlend.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{c5891a1b-574d-49da-af0e-bf7134183e73}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">TextureBlend</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>TextureBlend</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">TextureBlend.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 53 - 0
Externals/Graphics32/Examples/Blending/TextureBlend/createbundle.sh

@@ -0,0 +1,53 @@
+#!/bin/sh
+# Force Bourne shell in case tcsh is default.
+#
+appname=TextureBlend
+appfolder=$appname.app
+macosfolder=$appfolder/Contents/MacOS
+plistfile=$appfolder/Contents/Info.plist
+appfile=$appname
+#
+if ! [ -e $appfile ]
+then
+  echo "$appfile does not exist"
+elif [ -e $appfolder ]
+then
+  echo "$appfolder already exists"
+else
+  echo "Creating $appfolder..."
+  mkdir $appfolder
+  mkdir $appfolder/Contents
+  mkdir $appfolder/Contents/MacOS
+  mkdir $appfolder/Contents/Resources
+#
+# Instead of copying executable into .app folder after each compile,
+# simply create a symbolic link to executable.
+  ln -s ../../../$appname $macosfolder/$appname
+# Also create a symbolic link for the resource files
+  ln -s ../../../../../../Media $appfolder/Contents/Resources/Media
+#
+# Create PkgInfo file.
+  echo "APPL????" >$appfolder/Contents/PkgInfo
+#
+# Create information property list file (Info.plist).
+  echo '<?xml version="1.0" encoding="UTF-8"?>' >$plistfile
+  echo '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >>$plistfile
+  echo '<plist version="1.0">' >>$plistfile
+  echo '<dict>' >>$plistfile
+  echo '  <key>CFBundleDevelopmentRegion</key>' >>$plistfile
+  echo '  <string>English</string>' >>$plistfile
+  echo '  <key>CFBundleExecutable</key>' >>$plistfile
+  echo '  <string>'$appname'</string>' >>$plistfile
+  echo '  <key>CFBundleInfoDictionaryVersion</key>' >>$plistfile
+  echo '  <string>6.0</string>' >>$plistfile
+  echo '  <key>CFBundlePackageType</key>' >>$plistfile
+  echo '  <string>APPL</string>' >>$plistfile
+  echo '  <key>CFBundleSignature</key>' >>$plistfile
+  echo '  <string>????</string>' >>$plistfile
+  echo '  <key>CFBundleVersion</key>' >>$plistfile
+  echo '  <string>1.0</string>' >>$plistfile
+  echo '  <key>CSResourcesFileMapped</key>' >>$plistfile
+  echo '  <true/>' >>$plistfile
+  echo '</dict>' >>$plistfile
+  echo '</plist>' >>$plistfile
+fi

+ 13 - 0
Externals/Graphics32/Examples/Drawing/AntiAliasing/AntiAliasing.dpr

@@ -0,0 +1,13 @@
+program AntiAliasing;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFrmAntiAliasingTest, FrmAntiAliasingTest);
+  Application.Run;
+end.

+ 167 - 0
Externals/Graphics32/Examples/Drawing/AntiAliasing/AntiAliasing.dproj

@@ -0,0 +1,167 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>AntiAliasing.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{82a87652-f3f1-4f83-ac48-d4efb65a125c}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">AntiAliasing</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>AntiAliasing</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">AntiAliasing.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 25 - 0
Externals/Graphics32/Examples/Drawing/AntiAliasing/MainUnit.dfm

@@ -0,0 +1,25 @@
+object FrmAntiAliasingTest: TFrmAntiAliasingTest
+  Left = 0
+  Top = 0
+  Caption = 'Anti-Aliasing Test'
+  ClientHeight = 350
+  ClientWidth = 480
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  PixelsPerInch = 96
+  TextHeight = 13
+  object PaintBox32: TPaintBox32
+    Left = 0
+    Top = 0
+    Width = 480
+    Height = 350
+    Align = alClient
+    TabOrder = 0
+    OnPaintBuffer = PaintBox32PaintBuffer
+  end
+end

+ 260 - 0
Externals/Graphics32/Examples/Drawing/AntiAliasing/MainUnit.pas

@@ -0,0 +1,260 @@
+unit MainUnit;
+
+{$include GR32.inc}
+
+interface
+
+uses
+  {$IFNDEF FPC}Windows, {$ELSE} LCLIntf, LCLType, LMessages, {$ENDIF}
+  Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  GR32, GR32_Image, GR32_Polygons, GR32_ColorGradients;
+
+type
+  TFrmAntiAliasingTest = class(TForm)
+    PaintBox32: TPaintBox32;
+    procedure PaintBox32PaintBuffer(Sender: TObject);
+  end;
+
+var
+  FrmAntiAliasingTest: TFrmAntiAliasingTest;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Math,
+  Types,
+  GR32_Math,
+  GR32_Gamma,
+  GR32_VectorUtils;
+
+procedure TFrmAntiAliasingTest.PaintBox32PaintBuffer(Sender: TObject);
+
+  function ArrayOfFloat(Values: array of TFloat): TArrayOfFloat;
+  var
+    Index: Integer;
+  begin
+    SetLength(Result, Length(Values));
+    for Index := 0 to High(Values) do
+      Result[Index] := Values[Index];
+  end;
+
+  function IndexToColor32(Index: Integer): TColor32;
+  begin
+    Result := Color32(
+       $FF * (Index mod 2),         // red
+      ($FF * (Index mod 3)) shr 1,  // green
+      ($FF * (Index mod 5)) shr 2   // blue
+    );
+  end;
+
+var
+  W, H: Integer;
+  Center: TFloatPoint;
+  Points: TArrayOfFloatPoint;
+  Outline: TArrayOfFloatPoint;
+  Temp, MinCenter: TFloat;
+  Index: Integer;
+  LinGrad: TLinearGradientPolygonFiller;
+  Renderer: TPolygonRenderer32;
+
+const
+  CDeg2Rad = Pi / 180;
+
+  procedure DrawCircleLine;
+  var
+    Index: Integer;
+    Offset, Angle: TFloatPoint;
+  begin
+    // setup an efficient quadrature oscillator algorithm
+    Angle.X := 0;
+    Angle.Y := 1;
+    GR32_Math.SinCos(2 * CDeg2Rad, Offset.X, Offset.Y);
+    Offset.X := -Offset.X;
+
+    // set color
+    Renderer.Color := $33FFFFFF;
+
+    // keep the same center
+    Points[0] := FloatPoint(Center.X, Center.Y);
+
+    for Index := 180 downto 1 do
+    begin
+      // specify line end around the circle
+      Points[1] := FloatPoint(Center.X + MinCenter * Angle.X,
+        Center.Y + MinCenter * Angle.Y);
+
+      if Index < 90 then
+        Renderer.PolyPolygonFS(BuildPolyPolyline(BuildDashedLine(Points,
+          ArrayOfFloat([Index, Index])), False, 1))
+      else
+        Renderer.PolygonFS(BuildPolyline(Points, 1));
+
+      Temp := Angle.Y * Offset.Y - Angle.X * Offset.X;
+      Angle.X := Angle.X * Offset.Y + Angle.Y * Offset.X;
+      Angle.Y := Temp;
+    end;
+  end;
+
+  procedure DrawTriangles;
+  var
+    Index: Integer;
+  begin
+    // Triangles
+    SetLength(Points, 3);
+    Renderer.Filler := LinGrad;
+    for Index := 1 to 13 do
+    begin
+      Points[0] := FloatPoint(W - 150, H - 20 - Index * (Index + 1.5));
+      Points[1] := FloatPoint(W -  20, H - 20 - Index * (Index + 1));
+      Points[2] := FloatPoint(W -  20, H - 20 - Index * (Index + 2));
+
+      LinGrad.SimpleGradient(Points[0], clWhite32, Points[1], IndexToColor32(Index));
+      Renderer.PolygonFS(Points);
+    end;
+  end;
+
+  procedure DrawAlmostHorzVert;
+  const
+    LineCount = 20;
+  var
+    Index: Integer;
+  begin
+    Renderer.Color := clWhite32;
+    Renderer.Filler := nil;
+
+    for Index := 0 to LineCount do
+      Renderer.PolygonFS(
+        BuildPolyLine(Line(FloatPoint(20+Index*4, H-20), FloatPoint(20+Index*4 + Index/4, 200)), 0.5)
+      );
+
+    for Index := 0 to LineCount do
+      Renderer.PolygonFS(
+        BuildPolyLine(Line(FloatPoint(20, H-20-Index*4), FloatPoint(W div 2, H-20-Index*4 - Index/4)), 0.5)
+      );
+  end;
+
+begin
+  Paintbox32.Buffer.Clear($FF000000);
+
+  // cache width (W) and height (H) for faster access
+  W := Paintbox32.Width;
+  H := Paintbox32.Height;
+
+  // calculate the center point for a faster access
+  Center.X := 0.5 * W;
+  Center.Y := 0.5 * H;
+
+  // initialize some variables for a fast quadrature oscillator algorithm
+  MinCenter := Min(Center.X, Center.Y);
+
+  SetLength(Points, 2);
+
+  Renderer := TPolygonRenderer32VPR.Create;
+  Renderer.Bitmap := PaintBox32.Buffer;
+  try
+    DrawCircleLine;
+
+    // Top patterns
+    LinGrad := TLinearGradientPolygonFiller.Create;
+    try
+
+      LinGrad.Gradient.StartColor := clWhite32;
+
+      for Index := 1 to 20 do
+      begin
+        Renderer.Color := clWhite32;
+        Renderer.Filler := nil;
+
+        // integral point sizes 1..20
+        Outline := Circle(20.5 + Index * (Index + 1), 20.5, 0.5 * Index, 8 + Index);
+        Renderer.PolygonFS(Outline);
+
+        // fractional point sizes 0..2
+        Outline := Circle(18.5 + 4 * Index, 33.5, 0.05 * Index, 8);
+        Renderer.PolygonFS(Outline);
+
+        // fractional point positioning
+        Outline := Circle(18.4 + 4.1 * Index, 27.4 + 0.1 * Index, 0.5, 8);
+        Renderer.PolygonFS(Outline);
+
+        Renderer.Filler := LinGrad;
+        Points[0] := FloatPoint(20 + Index * (Index + 1), 40.5);
+        Points[1] := FloatPoint(20 + Index * (Index + 1) + (Index - 1) * 4, 100.5);
+        LinGrad.SimpleGradient(Points[0], clWhite32, Points[1], IndexToColor32(Index));
+        Outline := BuildPolyline(Points, Index, jsRound, esRound);
+        Renderer.PolygonFS(Outline);
+
+        // fractional line lengths H (red/blue)
+        LinGrad.Gradient.StartColor := $FF0000FF;
+        LinGrad.Gradient.EndColor := $FFFF0000;
+
+        Points[0] := FloatPoint(17.5 + 4 * Index, 107);
+        Points[1] := FloatPoint(17.5 + 4.15 * Index, 107);
+        LinGrad.SetPoints(Points[0], Points[1]);
+        Renderer.PolygonFS(BuildPolyline(Points, 1));
+
+        // fractional line lengths V (red/blue)
+        Points[0] := FloatPoint(18 + 4 * Index, 112.5);
+        Points[1] := FloatPoint(18 + 4.15 * Index, 112.5 + Index * 0.15);
+        LinGrad.SetPoints(Points[0], Points[1]);
+        Renderer.PolygonFS(BuildPolyline(Points, 1));
+
+        // fractional line positioning (red)
+        Points[0] := FloatPoint(21.5, 120 + (Index - 1) * 3.1);
+        Points[1] := FloatPoint(52.5, 120 + (Index - 1) * 3.1);
+        LinGrad.SimpleGradient(Points[0], $FFFF0000, Points[1], clWhite32);
+        Renderer.PolygonFS(BuildPolyline(Points, 1));
+
+        // fractional line width 2..0 (green)
+        Points[0] := FloatPoint(52.5, 118 + Index * 3);
+        Points[1] := FloatPoint(83.5, 118 + Index * 3);
+        LinGrad.SimpleGradient(Points[0], $FF00FF00, Points[1], clWhite32);
+        Outline := BuildPolyline(Points, 2 - (Index - 1) * 0.1, jsRound, esRound);
+        Renderer.PolygonFS(Outline);
+
+        // stippled fractional width 2..0 (blue)
+        Points[0] := FloatPoint(83.5, 119 + Index * 3);
+        Points[1] := FloatPoint(114.5, 119 + Index * 3);
+        LinGrad.SimpleGradient(Points[0], $FF0000FF, Points[1], clWhite32);
+        Renderer.PolyPolygonFS(BuildPolyPolyline(BuildDashedLine(Points,
+          ArrayOfFloat([3, 3])), False, 2 - (Index - 1) * 0.1));
+
+        Renderer.Color := clWhite32;
+        Renderer.Filler := nil;
+
+        // integral line width, horz aligned (mipmap test)
+        if Index < 10 then
+        begin
+          Points[0] := FloatPoint(125.5, 119.5 + (Index + 2) * (Index * 0.5));
+          Points[1] := FloatPoint(135.5, 119.5 + (Index + 2) * (Index * 0.5));
+          Outline := BuildPolyline(Points, Index, jsRound, esRound);
+          Renderer.PolygonFS(Outline);
+        end;
+
+        // fractional line positioning, 1 px H
+        Points[0] := FloatPoint(17.5 + 4.1 * Index - 0.1, 186);
+        Points[1] := FloatPoint(18.5 + 4.1 * Index - 0.1, 186);
+        Renderer.PolygonFS(BuildPolyline(Points, 1));
+
+        // fractional line width 0..2, 1 px H
+        Points[0] := FloatPoint(17.5 + 4 * Index, 192);
+        Points[1] := FloatPoint(18.5 + 4 * Index, 192);
+        Renderer.PolygonFS(BuildPolyline(Points, 0.1 * Index));
+      end;
+
+      DrawTriangles;
+
+      DrawAlmostHorzVert;
+      
+
+    finally
+      LinGrad.Free;
+    end;
+  finally
+    Renderer.Free;
+  end;
+end;
+
+end.

+ 1 - 0
Externals/Graphics32/Examples/Drawing/AntiAliasing/Media.rc

@@ -0,0 +1 @@
+MainIcon ICON "../../Media/GR32.ico"

+ 13 - 0
Externals/Graphics32/Examples/Drawing/ArrowHead/ArrowHead.dpr

@@ -0,0 +1,13 @@
+program ArrowHead;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas' {FmArrowHead};
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFmArrowHead, FmArrowHead);
+  Application.Run;
+end.

+ 169 - 0
Externals/Graphics32/Examples/Drawing/ArrowHead/ArrowHead.dproj

@@ -0,0 +1,169 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>ArrowHead.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{6d94c87d-6a65-4485-80a3-15a0f0c96b9e}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">ArrowHead</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>ArrowHead</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas">
+            <Form>FmArrowHead</Form>
+        </DCCReference>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">ArrowHead.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 152 - 0
Externals/Graphics32/Examples/Drawing/ArrowHead/MainUnit.dfm

@@ -0,0 +1,152 @@
+object FmArrowHead: TFmArrowHead
+  Left = 375
+  Top = 138
+  Caption = 'ArrowHead'
+  ClientHeight = 470
+  ClientWidth = 567
+  Color = clBtnFace
+  Font.Charset = ANSI_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -12
+  Font.Name = 'Arial'
+  Font.Style = []
+  KeyPreview = True
+  OldCreateOrder = False
+  OnCreate = FormCreate
+  OnDestroy = FormDestroy
+  PixelsPerInch = 96
+  TextHeight = 15
+  object ImgView32: TImgView32
+    Left = 173
+    Top = 0
+    Width = 394
+    Height = 470
+    Align = alClient
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baCustom
+    Scale = 1.000000000000000000
+    ScaleMode = smScale
+    ScrollBars.ShowHandleGrip = True
+    ScrollBars.Style = rbsDefault
+    ScrollBars.Size = 16
+    ScrollBars.Visibility = svHidden
+    OverSize = 0
+    TabOrder = 0
+    OnMouseDown = ImgView32MouseDown
+    OnMouseMove = ImgView32MouseMove
+    OnMouseUp = ImgView32MouseUp
+    OnResize = ImgView32Resize
+  end
+  object PnlControl: TPanel
+    Left = 0
+    Top = 0
+    Width = 173
+    Height = 470
+    Align = alLeft
+    TabOrder = 1
+    object LblArrowSize: TLabel
+      Left = 15
+      Top = 19
+      Width = 57
+      Height = 15
+      Caption = '&Arrow Size'
+      FocusControl = EdtArrowSize
+    end
+    object LblLineWidth: TLabel
+      Left = 16
+      Top = 315
+      Width = 58
+      Height = 15
+      Caption = 'Line &Width'
+      FocusControl = TbrLineWidth
+    end
+    object BtnClose: TButton
+      Left = 15
+      Top = 424
+      Width = 140
+      Height = 25
+      Cancel = True
+      Caption = '&Close'
+      TabOrder = 6
+      OnClick = BtnCloseClick
+    end
+    object RgpArrowStyle: TRadioGroup
+      Left = 15
+      Top = 69
+      Width = 140
+      Height = 131
+      Caption = 'Arrow &Style'
+      ItemIndex = 2
+      Items.Strings = (
+        'None'
+        '3 point'
+        '4 point'
+        'Diamond'
+        'Ellipse')
+      TabOrder = 1
+      OnClick = RgpArrowStyleClick
+    end
+    object EdtArrowSize: TEdit
+      Left = 15
+      Top = 36
+      Width = 140
+      Height = 23
+      TabOrder = 0
+      Text = '20'
+      OnChange = EdtArrowSizeChange
+    end
+    object RgpPosition: TRadioGroup
+      Left = 15
+      Top = 210
+      Width = 140
+      Height = 97
+      Caption = 'Arrow &Locations'
+      ItemIndex = 2
+      Items.Strings = (
+        'Arrow at start'
+        'Arrow at end'
+        'Arrow at both ends')
+      TabOrder = 2
+      OnClick = RgpArrowStyleClick
+    end
+    object TbrLineWidth: TTrackBar
+      Left = 9
+      Top = 335
+      Width = 153
+      Height = 31
+      Max = 8
+      Min = 1
+      Position = 3
+      TabOrder = 3
+      OnChange = TbrLineWidthChange
+    end
+    object TbrAnimationSpeed: TTrackBar
+      Left = 91
+      Top = 381
+      Width = 70
+      Height = 31
+      Max = 8
+      Min = 1
+      Position = 3
+      TabOrder = 5
+      TickStyle = tsNone
+      OnChange = TbrAnimationSpeedChange
+    end
+    object CbxAnimate: TCheckBox
+      Left = 15
+      Top = 384
+      Width = 69
+      Height = 17
+      Caption = 'Ani&mate'
+      TabOrder = 4
+      OnClick = CbxAnimateClick
+    end
+  end
+  object Animation: TTimer
+    Enabled = False
+    Interval = 30
+    OnTimer = AnimationTimer
+    Left = 184
+    Top = 16
+  end
+end

+ 523 - 0
Externals/Graphics32/Examples/Drawing/ArrowHead/MainUnit.pas

@@ -0,0 +1,523 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is ArrowHead Example for Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Angus Johnson < http://www.angusj.com >
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFDEF FPC} LCLIntf, LResources, {$ENDIF} SysUtils, Classes, Graphics,
+  Controls, Forms, StdCtrls, ExtCtrls, ComCtrls, GR32, GR32_Image, GR32_Layers,
+  GR32_Paths, GR32_Polygons, GR32_ArrowHeads;
+
+type
+  TFmArrowHead = class(TForm)
+    Animation: TTimer;
+    BtnClose: TButton;
+    CbxAnimate: TCheckBox;
+    EdtArrowSize: TEdit;
+    ImgView32: TImgView32;
+    LblArrowSize: TLabel;
+    LblLineWidth: TLabel;
+    PnlControl: TPanel;
+    RgpArrowStyle: TRadioGroup;
+    RgpPosition: TRadioGroup;
+    TbrAnimationSpeed: TTrackBar;
+    TbrLineWidth: TTrackBar;
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+    procedure AnimationTimer(Sender: TObject);
+    procedure BtnCloseClick(Sender: TObject);
+    procedure CbxAnimateClick(Sender: TObject);
+    procedure EdtArrowSizeChange(Sender: TObject);
+    procedure ImgView32MouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+    procedure ImgView32MouseUp(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+    procedure ImgView32MouseMove(Sender: TObject; Shift: TShiftState;
+      X, Y: Integer; Layer: TCustomLayer);
+    procedure ImgView32Resize(Sender: TObject);
+    procedure RgpArrowStyleClick(Sender: TObject);
+    procedure TbrAnimationSpeedChange(Sender: TObject);
+    procedure TbrLineWidthChange(Sender: TObject);
+  private
+    FArrowSize: Integer;
+    FBoxIndex: Integer;
+    FLastPos: TPoint;
+    FDashes: TArrayOfFloat;
+    FAnimationSpeed: Integer;
+    FBoxCenter: array [0..1] of TFloatPoint;
+    FVelocity: array [0..1] of TFloatPoint;
+    FPattern: array [0..1] of TBitmap32;
+    FBitmapFiller: TBitmapPolygonFiller;
+    procedure SetArrowSize(const Value: Integer);
+  protected
+    procedure ArrowSizeChanged; virtual;
+  public
+    procedure ReDraw;
+
+    property ArrowSize: Integer read FArrowSize write SetArrowSize;
+  end;
+
+var
+  FmArrowHead: TFmArrowHead;
+
+const
+  CBoxSize = 60;
+  CBorderSize = 10;
+  CBoxSizePlus = CBoxSize + CBorderSize;
+  CRad = (CBoxSize + CBorderSize) div 2;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Math, GR32_LowLevel, GR32_Geometry, GR32_VectorUtils, GR32_ColorGradients, Types;
+
+{ Miscellaneous functions }
+
+procedure ChangeSign(var Value: TFloat); {$IFDEF USEINLINING} inline; {$ENDIF}
+begin
+  Value := -Value;
+end;
+
+procedure SwapVelocities(var Value1, Value2: TFloat); {$IFDEF USEINLINING} inline; {$ENDIF}
+var
+  Val: TFloat;
+begin
+  Val := Value1;
+  Value1 := Value2;
+  Value2 := Val;
+end;
+
+function GetNearestPointOnBox(const Pt, BoxCenter: TFloatPoint;
+  const BoxPts: array of TFloatPoint): TFloatPoint;
+var
+  I, Index: Integer;
+  DistSqrd, DS: TFloat;
+begin
+  Index := 0;
+  DistSqrd := SqrDistance(BoxPts[0], Pt);
+  for I := 1 to High(BoxPts) do
+  begin
+    DS := SqrDistance(BoxPts[I], Pt);
+    if DS >= DistSqrd then Continue;
+    DistSqrd := DS;
+    Index := I;
+  end;
+  if Index = High(BoxPts) then I := 0 else I := Index + 1;
+  if not SegmentIntersect(Pt, BoxCenter, BoxPts[Index], BoxPts[I], Result) then
+  begin
+    if Index = 0 then I := High(BoxPts) else I := Index - 1;
+    if not SegmentIntersect(Pt, BoxCenter, BoxPts[Index], BoxPts[I], Result) then
+      Result := Pt;
+  end;
+end;
+
+function BoxesOverlap(const Box1Center, Box2Center: TFloatPoint;
+  BoxSize: TFloat): Boolean;
+begin
+  Result := (Abs(Box1Center.X - Box2Center.X) <= BoxSize) and
+    (Abs(Box1Center.Y - Box2Center.Y) <= BoxSize);
+end;
+
+function MakeBezierCurve(const CtrlPts: TArrayOfFloatPoint): TArrayOfFloatPoint;
+var
+  Index: Integer;
+  Path: TFlattenedPath;
+begin
+  Path := TFlattenedPath.Create;
+  try
+    Path.MoveTo(CtrlPts[0]);
+    for Index := 0 to (High(CtrlPts) - 3) div 3 do
+      Path.CurveTo(CtrlPts[Index * 3 + 1], CtrlPts[Index * 3 + 2], CtrlPts[Index * 3 + 3]);
+    Path.EndPath;
+    Result := Path.Path[0];
+  finally
+    Path.Free;
+  end;
+end;
+
+function MakeBox(CenterPt: TFloatPoint; Size: TFloat): TArrayOfFloatPoint;
+begin
+  Size := Size * 0.5;
+  SetLength(Result, 4);
+  Result[0] := OffsetPoint(CenterPt, -Size, -Size);
+  Result[1] := OffsetPoint(CenterPt,  Size, -Size);
+  Result[2] := OffsetPoint(CenterPt,  Size,  Size);
+  Result[3] := OffsetPoint(CenterPt, -Size,  Size);
+end;
+
+{ TFmArrowHead }
+
+procedure TFmArrowHead.FormCreate(Sender: TObject);
+begin
+  ImgView32.Bitmap.DrawMode := dmOpaque;
+  ImgView32.SetupBitmap(True, clWhite32);
+
+  FBoxIndex := -1;
+  FArrowSize := 20;
+  FDashes := [14, 3, 3, 3, 3, 3];
+  FBoxCenter[0] := FloatPoint(120, 100);
+  FBoxCenter[1] := FloatPoint(240, 300);
+  FAnimationSpeed := TbrAnimationSpeed.Position;
+  CbxAnimateClick(nil);
+
+  FPattern[0] := TBitmap32.Create;
+  FPattern[0].LoadFromResourceName(HInstance, 'PATTERN1');
+  FPattern[1] := TBitmap32.Create;
+  FPattern[1].LoadFromResourceName(HInstance, 'PATTERN2');
+
+  FBitmapFiller := TBitmapPolygonFiller.Create;
+
+  Redraw;
+end;
+
+procedure TFmArrowHead.FormDestroy(Sender: TObject);
+begin
+  FPattern[0].Free;
+  FPattern[1].Free;
+  FBitmapFiller.Free;
+end;
+
+procedure TFmArrowHead.ImgView32MouseDown(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+var
+  Index: Integer;
+begin
+  FBoxIndex := -1;
+  for Index := 0 to High(FBoxCenter) do
+    if GR32.PtInRect(
+      FloatRect(FBoxCenter[Index].X - CRad, FBoxCenter[Index].Y - CRad, FBoxCenter[Index].X + CRad, FBoxCenter[Index].Y + CRad),
+      GR32.Point(X, Y)) then
+    begin
+      FLastPos := GR32.Point(X, Y);
+      FBoxIndex := Index;
+      Exit;
+    end;
+end;
+
+procedure TFmArrowHead.ImgView32MouseMove(Sender: TObject;
+  Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+var
+  Index: Integer;
+begin
+  if FBoxIndex >= 0 then
+  begin
+    FBoxCenter[FBoxIndex].X := EnsureRange(FBoxCenter[FBoxIndex].X + X - FLastPos.X, CRad, ImgView32.Width - CRad);
+    FBoxCenter[FBoxIndex].Y := EnsureRange(FBoxCenter[FBoxIndex].Y + Y - FLastPos.Y, CRad, ImgView32.Height - CRad);
+    ReDraw;
+    FLastPos := GR32.Point(X, Y);
+  end
+  else
+  begin
+    for Index := 0 to High(FBoxCenter) do
+      if GR32.PtInRect(
+        FloatRect(FBoxCenter[Index].X - CRad, FBoxCenter[Index].Y - CRad, FBoxCenter[Index].X + CRad, FBoxCenter[Index].Y + CRad),
+        GR32.Point(X, Y)) then
+      begin
+        ImgView32.Cursor := crHandPoint;
+        Exit;
+      end;
+    ImgView32.Cursor := crArrow;
+  end;
+end;
+
+procedure TFmArrowHead.ImgView32MouseUp(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+  FBoxIndex := -1;
+end;
+
+procedure TFmArrowHead.ImgView32Resize(Sender: TObject);
+begin
+  ImgView32.Bitmap.SetSize(ImgView32.Width, ImgView32.Height);
+  ReDraw;
+end;
+
+procedure TFmArrowHead.ReDraw;
+var
+  Box : array [0..1] of TArrayOfFloatPoint;
+  Poly, ArrowPts: TArrayOfFloatPoint;
+  StartPoint, EndPoint, StartOffsetPt, EndOffsetPt: TFloatPoint;
+  Delta: TFloatPoint;
+  Arrow: TArrowHeadAbstract;
+  GradientFiller: TLinearGradientPolygonFiller;
+  ArrowOverlap: integer;
+const
+  StartArrowColor: TColor32 = $60009900;
+  StartArrowPenColor: TColor32 = $FF339900;
+  EndArrowColor: TColor32 = $600000AA;
+  EndArrowPenColor: TColor32 = $FF0033AA;
+begin
+  ImgView32.Bitmap.Clear(clWhite32);
+
+
+  (*
+  ** Stippled boxes
+  *)
+
+  Box[0] := MakeBox(FBoxCenter[0], CBoxSize);
+  Box[1] := MakeBox(FBoxCenter[1], CBoxSize);
+
+  FBitmapFiller.Pattern := FPattern[0];
+  DashLineFS(ImgView32.Bitmap, Box[0], FDashes, FBitmapFiller, EndArrowPenColor, True, CBorderSize, 1.5);
+
+  FBitmapFiller.Pattern := FPattern[1];
+  DashLineFS(ImgView32.Bitmap, Box[1], FDashes, FBitmapFiller, EndArrowPenColor, True, CBorderSize, 1.5);
+
+
+  (*
+  ** Construct a bezier line connecting the two boxes
+  *)
+
+  // Find line start and end point;
+  // Given a box center point, and the size of the box plus the border, calculate the outer boxes.
+  Box[0] := MakeBox(FBoxCenter[0], CBoxSizePlus);
+  Box[1] := MakeBox(FBoxCenter[1], CBoxSizePlus);
+  // If the boxes overlap we use the box center as the start and end points...
+  if BoxesOverlap(FBoxCenter[0], FBoxCenter[1], CBoxSizePlus) then
+  begin
+    StartPoint := FBoxCenter[0];
+    EndPoint := FBoxCenter[1];
+  end else
+  // ...otherwise we use nearest point on the border;
+  begin
+    StartPoint := GetNearestPointOnBox(FBoxCenter[1], FBoxCenter[0], Box[0]);
+    EndPoint := GetNearestPointOnBox(FBoxCenter[0], FBoxCenter[1], Box[1]);
+  end;
+
+  // Calculate the bezier control points;
+  Delta.X := StartPoint.X - FBoxCenter[0].X;
+  Delta.Y := StartPoint.Y - FBoxCenter[0].Y;
+  if Abs(Delta.X) > Abs(Delta.Y) then
+    StartOffsetPt := FloatPoint(StartPoint.X + Delta.X * 2, StartPoint.Y)
+  else
+    StartOffsetPt := FloatPoint(StartPoint.X, StartPoint.Y + Delta.Y *2);
+
+  Delta.X := EndPoint.X - FBoxCenter[1].X;
+  Delta.Y := EndPoint.Y - FBoxCenter[1].Y;
+  if Abs(Delta.X) > Abs(Delta.Y) then
+    EndOffsetPt := FloatPoint(EndPoint.X + Delta.X * 2, EndPoint.Y)
+  else
+    EndOffsetPt := FloatPoint(EndPoint.X, EndPoint.Y + Delta.Y * 2);
+
+  // Create a polyline and from that, a bezier
+  Poly := BuildPolygonF([
+    StartPoint.X, StartPoint.Y,
+    StartOffsetPt.X, StartOffsetPt.Y,
+    EndOffsetPt.X, EndOffsetPt.Y,
+    EndPoint.X, EndPoint.Y]);
+  Poly := MakeBezierCurve(Poly);
+
+  (*
+  ** Arrow heads
+  *)
+
+  case RgpArrowStyle.ItemIndex of
+    1: Arrow := TArrowHeadSimple.Create(ArrowSize);
+    2: Arrow := TArrowHeadFourPt.Create(ArrowSize);
+    3: Arrow := TArrowHeadDiamond.Create(ArrowSize);
+    4: Arrow := TArrowHeadCircle.Create(ArrowSize);
+  else
+    Arrow := nil;
+  end;
+
+
+  (*
+  ** Draw arrow head(s) and a gradient connecting line
+  **   or
+  ** Draw a solid connecting line
+  *)
+
+  // Draw arrow head(s) and a gradient connecting line
+  if (Arrow <> nil) then
+  begin
+    // Shorten line path at specified end(s) so arrow doesn't overlap box border;
+    ArrowOverlap := ArrowSize;
+
+    if (RgpArrowStyle.ItemIndex <> 4) then
+      // Note: Because of the miter the arrow might still overlap the border a few pixels.
+      Inc(ArrowOverlap, TbrLineWidth.Position)
+    else
+      Inc(ArrowOverlap, (TbrLineWidth.Position+1) div 2);
+
+    case RgpPosition.ItemIndex of
+      0: Poly := Shorten(Poly, ArrowOverlap, lpStart);
+      1: Poly := Shorten(Poly, ArrowOverlap, lpEnd);
+      2: Poly := Shorten(Poly, ArrowOverlap, lpBoth);
+    end;
+
+    // Draw a gradient connecting line;
+    GradientFiller := TLinearGradientPolygonFiller.Create;
+    try
+      GradientFiller.SimpleGradient(Poly[0], StartArrowPenColor, Poly[High(Poly)], EndArrowPenColor);
+      PolylineFS(ImgView32.Bitmap, Poly, GradientFiller, False, TbrLineWidth.Position);
+    finally
+      GradientFiller.Free;
+    end;
+
+    // Draw arrow(s);
+    // Start arrow head...
+    if RgpPosition.ItemIndex <> 1 then
+    begin
+      ArrowPts := Arrow.GetPoints(Poly, False);
+      // Brush
+      PolygonFS(ImgView32.Bitmap, ArrowPts, StartArrowColor);
+      // Stroke
+      PolylineFS(ImgView32.Bitmap, ArrowPts, StartArrowPenColor, True, TbrLineWidth.Position);
+    end;
+    // End arrow head...
+    if RgpPosition.ItemIndex <> 0 then
+    begin
+      ArrowPts := Arrow.GetPoints(Poly, True);
+      // Brush
+      PolygonFS(ImgView32.Bitmap, ArrowPts, EndArrowColor);
+      // Stroke
+      PolylineFS(ImgView32.Bitmap, ArrowPts, EndArrowPenColor, True, TbrLineWidth.Position);
+    end;
+  end else
+  // Draw a solid connecting line
+    PolylineFS(ImgView32.Bitmap, Poly, clBlack32, False, TbrLineWidth.Position);
+end;
+
+procedure TFmArrowHead.RgpArrowStyleClick(Sender: TObject);
+begin
+  ReDraw;
+end;
+
+procedure TFmArrowHead.EdtArrowSizeChange(Sender: TObject);
+begin
+  ArrowSize := EnsureRange(StrToIntDef(EdtArrowSize.Text, ArrowSize), 5, 40);
+end;
+
+procedure TFmArrowHead.BtnCloseClick(Sender: TObject);
+begin
+  Close;
+end;
+
+procedure TFmArrowHead.CbxAnimateClick(Sender: TObject);
+begin
+  Animation.Enabled := CbxAnimate.Checked;
+  Randomize;
+  FVelocity[0] := FloatPoint((2 * Random - 1) * FAnimationSpeed,
+    (2 * Random -1) * FAnimationSpeed);
+  FVelocity[1] := FloatPoint((2 * Random - 1) * FAnimationSpeed,
+    (2 * Random -1) * FAnimationSpeed);
+end;
+
+procedure TFmArrowHead.TbrAnimationSpeedChange(Sender: TObject);
+var
+  SpeedRatio: TFloat;
+begin
+  if not Animation.Enabled then Exit;
+  SpeedRatio := TbrAnimationSpeed.Position / FAnimationSpeed;
+  FAnimationSpeed := TbrAnimationSpeed.Position;
+  with FVelocity[0] do
+  begin
+    X := X * SpeedRatio;
+    Y := Y * SpeedRatio;
+  end;
+  with FVelocity[1] do
+  begin
+    X := X * SpeedRatio;
+    Y := Y * SpeedRatio;
+  end;
+end;
+
+procedure TFmArrowHead.AnimationTimer(Sender: TObject);
+var
+  Index: Integer;
+  NextCenter: array [0..1] of TFloatPoint;
+begin
+  if FBoxIndex >= 0 then Exit;
+
+  // move boxes ...
+  FBoxCenter[0] := OffsetPoint(FBoxCenter[0], FVelocity[0].X, FVelocity[0].Y);
+  FBoxCenter[1] := OffsetPoint(FBoxCenter[1], FVelocity[1].X, FVelocity[1].Y);
+  ReDraw;
+
+  // update velocities where there are collisions ...
+
+  NextCenter[0] := OffsetPoint(FBoxCenter[0], FVelocity[0].X, FVelocity[0].Y);
+  NextCenter[1] := OffsetPoint(FBoxCenter[1], FVelocity[1].X, FVelocity[1].Y);
+  if BoxesOverlap(NextCenter[0], NextCenter[1], CBoxSizePlus) then
+  begin
+    // manage box collisions ...
+    if (Abs(FBoxCenter[0].X - FBoxCenter[1].X) > CBoxSizePlus) then
+      SwapVelocities(FVelocity[0].X, FVelocity[1].X);
+    if (Abs(FBoxCenter[0].Y - FBoxCenter[1].Y) > CBoxSizePlus) then
+      SwapVelocities(FVelocity[0].Y, FVelocity[1].Y);
+    NextCenter[0] := OffsetPoint(FBoxCenter[0], FVelocity[0].X, FVelocity[0].Y);
+    NextCenter[1] := OffsetPoint(FBoxCenter[1], FVelocity[1].X, FVelocity[1].Y);
+  end;
+
+  // manage wall collisions ...
+  for Index := 0 to High(FBoxCenter) do
+  begin
+    if (NextCenter[Index].X + CRad > ImgView32.Width) then
+      FVelocity[Index].X := -Abs(FVelocity[Index].X)
+    else
+    if (NextCenter[Index].X - CRad < 0) then
+      FVelocity[Index].X := Abs(FVelocity[Index].X);
+
+    if (NextCenter[Index].Y + CRad > ImgView32.Height) then
+      FVelocity[Index].Y := -Abs(FVelocity[Index].Y)
+    else
+    if (NextCenter[Index].Y - CRad < 0) then
+      FVelocity[Index].Y := Abs(FVelocity[Index].Y);
+  end;
+end;
+
+procedure TFmArrowHead.SetArrowSize(const Value: Integer);
+begin
+  if FArrowSize <> Value then
+  begin
+    FArrowSize := Value;
+    ArrowSizeChanged;
+  end;
+end;
+
+procedure TFmArrowHead.ArrowSizeChanged;
+begin
+  Redraw;
+end;
+
+procedure TFmArrowHead.TbrLineWidthChange(Sender: TObject);
+begin
+  Redraw;
+end;
+
+end.

+ 3 - 0
Externals/Graphics32/Examples/Drawing/ArrowHead/Media.rc

@@ -0,0 +1,3 @@
+MainIcon ICON "../../Media/GR32.ico"
+Pattern1 BITMAP "../../Media/Pattern1.bmp"
+Pattern2 BITMAP "../../Media/Pattern2.bmp"

+ 16 - 0
Externals/Graphics32/Examples/Drawing/Benchmark/Benchmark.dpr

@@ -0,0 +1,16 @@
+program Benchmark;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+{.$R '..\..\manifest.res'}
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TMainForm, MainForm);
+  Application.Run;
+end.
+

+ 167 - 0
Externals/Graphics32/Examples/Drawing/Benchmark/Benchmark.dproj

@@ -0,0 +1,167 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>Benchmark.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{0aad6a54-6fc4-4792-a8fa-f6e2c489e5ff}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">Benchmark</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>Benchmark</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">Benchmark.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 3565 - 0
Externals/Graphics32/Examples/Drawing/Benchmark/Blend2D.Api.pas

@@ -0,0 +1,3565 @@
+unit Blend2D.Api;
+{ Blend2D for Delphi.
+  Based on Blend2D beta 12 }
+
+{ This unit is partially generated by Chet:
+  https://github.com/neslib/Chet }
+
+interface
+
+const
+  {$IF Defined(WIN32)}
+  LIB_BLEND2D = 'blend2d_win32.dll';
+  _PU = '';
+  {$ELSEIF Defined(WIN64)}
+  LIB_BLEND2D = 'blend2d_win64.dll';
+  _PU = '';
+  {$ELSEIF Defined(MACOS64) and not Defined(IOS)}
+    {$MESSAGE Error 'Blend2D for macOS not available yet'}
+//  LIB_BLEND2D = 'libblend2d_mac64.a';
+//  _PU = '';
+  {$ELSEIF Defined(IOS64)}
+    {$MESSAGE Error 'Blend2D for iOS not available yet'}
+  {$ELSEIF Defined(ANDROID)}
+    {$MESSAGE Error 'Blend2D for Android not available yet'}
+  {$ELSE}
+    {$MESSAGE Error 'Unsupported platform'}
+  {$ENDIF}
+
+type
+  PUInt8     = PByte;
+  PPUInt8    = ^PByte;
+  PUInt32    = ^UInt32;
+  PPUTF8Char = ^PUTF8Char;
+
+const
+  BL_VERSION    = (0 shl 16) or (0 shl 8) or 1;
+  BL_BYTE_ORDER = 1234;
+
+type
+  BLResult   = UInt32;
+  BLTag      = UInt32;
+  BLUniqueId = UInt64;
+  BLBitWord  = NativeUInt;
+
+type
+  _PBLTag = ^BLTag;
+
+function BL_MAKE_TAG(const A, B, C, D: Byte): BLTag; inline;
+
+type
+  PBLFileCore = Pointer;
+
+type
+  BLDestroyImplFunc = procedure(impl, destroyData: Pointer); cdecl;
+
+type
+  BLBooleanOp = Integer;
+
+const
+  BL_BOOLEAN_OP_COPY  = 0;
+  BL_BOOLEAN_OP_AND   = 1;
+  BL_BOOLEAN_OP_OR    = 2;
+  BL_BOOLEAN_OP_XOR   = 3;
+  BL_BOOLEAN_OP_SUB   = 4;
+  BL_BOOLEAN_OP_COUNT = 5;
+
+type
+  BLByteOrder = Integer;
+
+const
+  BL_BYTE_ORDER_LE      = 0;
+  BL_BYTE_ORDER_BE      = 1;
+  BL_BYTE_ORDER_NATIVE  = BL_BYTE_ORDER_LE;
+  BL_BYTE_ORDER_SWAPPED = BL_BYTE_ORDER_BE;
+
+type
+  BLContextProperty = Integer;
+
+const
+  BL_CONTEXT_PROPERTY_THREAD_COUNT            = 0;
+  BL_CONTEXT_PROPERTY_ACCUMULATED_ERROR_FLAGS = 10;
+
+type
+  BLContextErrorFlags = Cardinal;
+
+const
+  BL_CONTEXT_ERROR_FLAG_INVALID_VALUE         = $00000001;
+  BL_CONTEXT_ERROR_FLAG_INVALID_STATE         = $00000002;
+  BL_CONTEXT_ERROR_FLAG_INVALID_GEOMETRY      = $00000004;
+  BL_CONTEXT_ERROR_FLAG_INVALID_GLYPH         = $00000008;
+  BL_CONTEXT_ERROR_FLAG_INVALID_FONT          = $00000010;
+  BL_CONTEXT_ERROR_FLAG_THREAD_POOL_EXHAUSTED = $20000000;
+  BL_CONTEXT_ERROR_FLAG_OUT_OF_MEMORY         = $40000000;
+  BL_CONTEXT_ERROR_FLAG_UNKNOWN_ERROR         = $80000000;
+
+type
+  BLClipMode = Integer;
+
+const
+  BL_CLIP_MODE_ALIGNED_RECT   = 0;
+  BL_CLIP_MODE_UNALIGNED_RECT = 1;
+  BL_CLIP_MODE_MASK           = 2;
+  BL_CLIP_MODE_COUNT          = 3;
+
+type
+  BLCompOp = Integer;
+
+const
+  BL_COMP_OP_SRC_OVER     = 0;
+  BL_COMP_OP_SRC_COPY     = 1;
+  BL_COMP_OP_SRC_IN       = 2;
+  BL_COMP_OP_SRC_OUT      = 3;
+  BL_COMP_OP_SRC_ATOP     = 4;
+  BL_COMP_OP_DST_OVER     = 5;
+  BL_COMP_OP_DST_COPY     = 6;
+  BL_COMP_OP_DST_IN       = 7;
+  BL_COMP_OP_DST_OUT      = 8;
+  BL_COMP_OP_DST_ATOP     = 9;
+  BL_COMP_OP_XOR          = 10;
+  BL_COMP_OP_CLEAR        = 11;
+  BL_COMP_OP_PLUS         = 12;
+  BL_COMP_OP_MINUS        = 13;
+  BL_COMP_OP_MODULATE     = 14;
+  BL_COMP_OP_MULTIPLY     = 15;
+  BL_COMP_OP_SCREEN       = 16;
+  BL_COMP_OP_OVERLAY      = 17;
+  BL_COMP_OP_DARKEN       = 18;
+  BL_COMP_OP_LIGHTEN      = 19;
+  BL_COMP_OP_COLOR_DODGE  = 20;
+  BL_COMP_OP_COLOR_BURN   = 21;
+  BL_COMP_OP_LINEAR_BURN  = 22;
+  BL_COMP_OP_LINEAR_LIGHT = 23;
+  BL_COMP_OP_PIN_LIGHT    = 24;
+  BL_COMP_OP_HARD_LIGHT   = 25;
+  BL_COMP_OP_SOFT_LIGHT   = 26;
+  BL_COMP_OP_DIFFERENCE   = 27;
+  BL_COMP_OP_EXCLUSION    = 28;
+  BL_COMP_OP_COUNT        = 29;
+
+type
+  BLContextCreateFlags = Integer;
+
+const
+  BL_CONTEXT_CREATE_FLAG_FALLBACK_TO_SYNC      = $00000008;
+  BL_CONTEXT_CREATE_FLAG_ISOLATED_THREAD_POOL  = $01000000;
+  BL_CONTEXT_CREATE_FLAG_ISOLATED_JIT          = $02000000;
+  BL_CONTEXT_CREATE_FLAG_OVERRIDE_CPU_FEATURES = $04000000;
+
+type
+  BLContextFlushFlags = Integer;
+
+const
+  BL_CONTEXT_FLUSH_SYNC = $80000000;
+
+type
+  BLContextHint = Integer;
+
+const
+  BL_CONTEXT_HINT_RENDERING_QUALITY = 0;
+  BL_CONTEXT_HINT_GRADIENT_QUALITY  = 1;
+  BL_CONTEXT_HINT_PATTERN_QUALITY   = 2;
+  BL_CONTEXT_HINT_COUNT             = 8;
+
+type
+  BLContextOpType = Integer;
+
+const
+  BL_CONTEXT_OP_TYPE_FILL   = 0;
+  BL_CONTEXT_OP_TYPE_STROKE = 1;
+  BL_CONTEXT_OP_TYPE_COUNT  = 2;
+
+type
+  BLContextType = Integer;
+
+const
+  BL_CONTEXT_TYPE_NONE   = 0;
+  BL_CONTEXT_TYPE_DUMMY  = 1;
+  BL_CONTEXT_TYPE_RASTER = 3;
+  BL_CONTEXT_TYPE_COUNT  = 4;
+
+type
+  BLDataAccessFlags = Integer;
+
+const
+  BL_DATA_ACCESS_READ  = 1;
+  BL_DATA_ACCESS_WRITE = 2;
+  BL_DATA_ACCESS_RW    = 3;
+
+type
+  BLDataSourceType = Integer;
+
+const
+  BL_DATA_SOURCE_TYPE_NONE   = 0;
+  BL_DATA_SOURCE_TYPE_MEMORY = 1;
+  BL_DATA_SOURCE_TYPE_FILE   = 2;
+  BL_DATA_SOURCE_TYPE_CUSTOM = 3;
+  BL_DATA_SOURCE_TYPE_COUNT  = 4;
+
+type
+  BLExtendMode = Integer;
+
+const
+  BL_EXTEND_MODE_PAD                 = 0;
+  BL_EXTEND_MODE_REPEAT              = 1;
+  BL_EXTEND_MODE_REFLECT             = 2;
+  BL_EXTEND_MODE_PAD_X_PAD_Y         = 0;
+  BL_EXTEND_MODE_REPEAT_X_REPEAT_Y   = 1;
+  BL_EXTEND_MODE_REFLECT_X_REFLECT_Y = 2;
+  BL_EXTEND_MODE_PAD_X_REPEAT_Y      = 3;
+  BL_EXTEND_MODE_PAD_X_REFLECT_Y     = 4;
+  BL_EXTEND_MODE_REPEAT_X_PAD_Y      = 5;
+  BL_EXTEND_MODE_REPEAT_X_REFLECT_Y  = 6;
+  BL_EXTEND_MODE_REFLECT_X_PAD_Y     = 7;
+  BL_EXTEND_MODE_REFLECT_X_REPEAT_Y  = 8;
+  BL_EXTEND_MODE_SIMPLE_COUNT        = 3;
+  BL_EXTEND_MODE_COMPLEX_COUNT       = 9;
+
+type
+  BLFillRule = Integer;
+
+const
+  BL_FILL_RULE_NON_ZERO = 0;
+  BL_FILL_RULE_EVEN_ODD = 1;
+  BL_FILL_RULE_COUNT    = 2;
+
+type
+  BLFlattenMode = Integer;
+
+const
+  BL_FLATTEN_MODE_DEFAULT   = 0;
+  BL_FLATTEN_MODE_RECURSIVE = 1;
+
+type
+  BLFontDataFlags = Integer;
+
+const
+  BL_FONT_DATA_FLAG_COLLECTION = 1;
+
+type
+  BLFontFaceDiagFlags = Integer;
+
+const
+  BL_FONT_FACE_DIAG_WRONG_NAME_DATA   = 1;
+  BL_FONT_FACE_DIAG_FIXED_NAME_DATA   = 2;
+  BL_FONT_FACE_DIAG_WRONG_KERN_DATA   = 4;
+  BL_FONT_FACE_DIAG_FIXED_KERN_DATA   = 8;
+  BL_FONT_FACE_DIAG_WRONG_CMAP_DATA   = 16;
+  BL_FONT_FACE_DIAG_WRONG_CMAP_FORMAT = 32;
+  BL_FONT_FACE_DIAG_WRONG_GDEF_DATA   = 256;
+  BL_FONT_FACE_DIAG_WRONG_GPOS_DATA   = 1024;
+  BL_FONT_FACE_DIAG_WRONG_GSUB_DATA   = 4096;
+
+type
+  BLFontFaceFlags = Integer;
+
+const
+  BL_FONT_FACE_FLAG_TYPOGRAPHIC_NAMES     = $00000001;
+  BL_FONT_FACE_FLAG_TYPOGRAPHIC_METRICS   = $00000002;
+  BL_FONT_FACE_FLAG_CHAR_TO_GLYPH_MAPPING = $00000004;
+  BL_FONT_FACE_FLAG_HORIZONTAL_METRICS    = $00000010;
+  BL_FONT_FACE_FLAG_VERTICAL_METRICS      = $00000020;
+  BL_FONT_FACE_FLAG_HORIZONTAL_KERNING    = $00000040;
+  BL_FONT_FACE_FLAG_VERTICAL_KERNING      = $00000080;
+  BL_FONT_FACE_FLAG_OPENTYPE_FEATURES     = $00000100;
+  BL_FONT_FACE_FLAG_PANOSE_DATA           = $00000200;
+  BL_FONT_FACE_FLAG_UNICODE_COVERAGE      = $00000400;
+  BL_FONT_FACE_FLAG_BASELINE_Y_EQUALS_0   = $00001000;
+  BL_FONT_FACE_FLAG_LSB_POINT_X_EQUALS_0  = $00002000;
+  BL_FONT_FACE_FLAG_VARIATION_SEQUENCES   = $10000000;
+  BL_FONT_FACE_FLAG_OPENTYPE_VARIATIONS   = $20000000;
+  BL_FONT_FACE_FLAG_SYMBOL_FONT           = $40000000;
+  BL_FONT_FACE_FLAG_LAST_RESORT_FONT      = $80000000;
+
+type
+  BLFontFaceType = Integer;
+
+const
+  BL_FONT_FACE_TYPE_NONE     = 0;
+  BL_FONT_FACE_TYPE_OPENTYPE = 1;
+  BL_FONT_FACE_TYPE_COUNT    = 2;
+
+type
+  BLFontOutlineType = Integer;
+
+const
+  BL_FONT_OUTLINE_TYPE_NONE     = 0;
+  BL_FONT_OUTLINE_TYPE_TRUETYPE = 1;
+  BL_FONT_OUTLINE_TYPE_CFF      = 2;
+  BL_FONT_OUTLINE_TYPE_CFF2     = 3;
+
+type
+  BLFontStretch = Integer;
+
+const
+  BL_FONT_STRETCH_ULTRA_CONDENSED = 1;
+  BL_FONT_STRETCH_EXTRA_CONDENSED = 2;
+  BL_FONT_STRETCH_CONDENSED       = 3;
+  BL_FONT_STRETCH_SEMI_CONDENSED  = 4;
+  BL_FONT_STRETCH_NORMAL          = 5;
+  BL_FONT_STRETCH_SEMI_EXPANDED   = 6;
+  BL_FONT_STRETCH_EXPANDED        = 7;
+  BL_FONT_STRETCH_EXTRA_EXPANDED = 8;
+  BL_FONT_STRETCH_ULTRA_EXPANDED = 9;
+
+type
+  BLFontStringId = Integer;
+
+const
+  BL_FONT_STRING_COPYRIGHT_NOTICE              = 0;
+  BL_FONT_STRING_FAMILY_NAME                   = 1;
+  BL_FONT_STRING_SUBFAMILY_NAME                = 2;
+  BL_FONT_STRING_UNIQUE_IDENTIFIER             = 3;
+  BL_FONT_STRING_FULL_NAME                     = 4;
+  BL_FONT_STRING_VERSION_STRING                = 5;
+  BL_FONT_STRING_POST_SCRIPT_NAME              = 6;
+  BL_FONT_STRING_TRADEMARK                     = 7;
+  BL_FONT_STRING_MANUFACTURER_NAME             = 8;
+  BL_FONT_STRING_DESIGNER_NAME                 = 9;
+  BL_FONT_STRING_DESCRIPTION                   = 10;
+  BL_FONT_STRING_VENDOR_URL                    = 11;
+  BL_FONT_STRING_DESIGNER_URL                  = 12;
+  BL_FONT_STRING_LICENSE_DESCRIPTION           = 13;
+  BL_FONT_STRING_LICENSE_INFO_URL              = 14;
+  BL_FONT_STRING_RESERVED                      = 15;
+  BL_FONT_STRING_TYPOGRAPHIC_FAMILY_NAME       = 16;
+  BL_FONT_STRING_TYPOGRAPHIC_SUBFAMILY_NAME    = 17;
+  BL_FONT_STRING_COMPATIBLE_FULL_NAME          = 18;
+  BL_FONT_STRING_SAMPLE_TEXT                   = 19;
+  BL_FONT_STRING_POST_SCRIPT_CID_NAME          = 20;
+  BL_FONT_STRING_WWS_FAMILY_NAME               = 21;
+  BL_FONT_STRING_WWS_SUBFAMILY_NAME            = 22;
+  BL_FONT_STRING_LIGHT_BACKGROUND_PALETTE      = 23;
+  BL_FONT_STRING_DARK_BACKGROUND_PALETTE       = 24;
+  BL_FONT_STRING_VARIATIONS_POST_SCRIPT_PREFIX = 25;
+  BL_FONT_STRING_COMMON_COUNT                  = 26;
+  BL_FONT_STRING_CUSTOM_START_INDEX            = 255;
+
+type
+  BLFontStyle = Integer;
+
+const
+  BL_FONT_STYLE_NORMAL  = 0;
+  BL_FONT_STYLE_OBLIQUE = 1;
+  BL_FONT_STYLE_ITALIC  = 2;
+  BL_FONT_STYLE_COUNT   = 3;
+
+type
+  BLFontUnicodeCoverageIndex = Integer;
+
+const
+  BL_FONT_UC_INDEX_BASIC_LATIN                             = 0;
+  BL_FONT_UC_INDEX_LATIN1_SUPPLEMENT                       = 1;
+  BL_FONT_UC_INDEX_LATIN_EXTENDED_A                        = 2;
+  BL_FONT_UC_INDEX_LATIN_EXTENDED_B                        = 3;
+  BL_FONT_UC_INDEX_IPA_EXTENSIONS                          = 4;
+  BL_FONT_UC_INDEX_SPACING_MODIFIER_LETTERS                = 5;
+  BL_FONT_UC_INDEX_COMBINING_DIACRITICAL_MARKS             = 6;
+  BL_FONT_UC_INDEX_GREEK_AND_COPTIC                        = 7;
+  BL_FONT_UC_INDEX_COPTIC                                  = 8;
+  BL_FONT_UC_INDEX_CYRILLIC                                = 9;
+  BL_FONT_UC_INDEX_ARMENIAN                                = 10;
+  BL_FONT_UC_INDEX_HEBREW                                  = 11;
+  BL_FONT_UC_INDEX_VAI                                     = 12;
+  BL_FONT_UC_INDEX_ARABIC                                  = 13;
+  BL_FONT_UC_INDEX_NKO                                     = 14;
+  BL_FONT_UC_INDEX_DEVANAGARI                              = 15;
+  BL_FONT_UC_INDEX_BENGALI                                 = 16;
+  BL_FONT_UC_INDEX_GURMUKHI                                = 17;
+  BL_FONT_UC_INDEX_GUJARATI                                = 18;
+  BL_FONT_UC_INDEX_ORIYA                                   = 19;
+  BL_FONT_UC_INDEX_TAMIL                                   = 20;
+  BL_FONT_UC_INDEX_TELUGU                                  = 21;
+  BL_FONT_UC_INDEX_KANNADA                                 = 22;
+  BL_FONT_UC_INDEX_MALAYALAM                               = 23;
+  BL_FONT_UC_INDEX_THAI                                    = 24;
+  BL_FONT_UC_INDEX_LAO                                     = 25;
+  BL_FONT_UC_INDEX_GEORGIAN                                = 26;
+  BL_FONT_UC_INDEX_BALINESE                                = 27;
+  BL_FONT_UC_INDEX_HANGUL_JAMO                             = 28;
+  BL_FONT_UC_INDEX_LATIN_EXTENDED_ADDITIONAL               = 29;
+  BL_FONT_UC_INDEX_GREEK_EXTENDED                          = 30;
+  BL_FONT_UC_INDEX_GENERAL_PUNCTUATION                     = 31;
+  BL_FONT_UC_INDEX_SUPERSCRIPTS_AND_SUBSCRIPTS             = 32;
+  BL_FONT_UC_INDEX_CURRENCY_SYMBOLS                        = 33;
+  BL_FONT_UC_INDEX_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS = 34;
+  BL_FONT_UC_INDEX_LETTERLIKE_SYMBOLS                      = 35;
+  BL_FONT_UC_INDEX_NUMBER_FORMS                            = 36;
+  BL_FONT_UC_INDEX_ARROWS                                  = 37;
+  BL_FONT_UC_INDEX_MATHEMATICAL_OPERATORS                  = 38;
+  BL_FONT_UC_INDEX_MISCELLANEOUS_TECHNICAL                 = 39;
+  BL_FONT_UC_INDEX_CONTROL_PICTURES                        = 40;
+  BL_FONT_UC_INDEX_OPTICAL_CHARACTER_RECOGNITION           = 41;
+  BL_FONT_UC_INDEX_ENCLOSED_ALPHANUMERICS                  = 42;
+  BL_FONT_UC_INDEX_BOX_DRAWING                             = 43;
+  BL_FONT_UC_INDEX_BLOCK_ELEMENTS                          = 44;
+  BL_FONT_UC_INDEX_GEOMETRIC_SHAPES                        = 45;
+  BL_FONT_UC_INDEX_MISCELLANEOUS_SYMBOLS                   = 46;
+  BL_FONT_UC_INDEX_DINGBATS                                = 47;
+  BL_FONT_UC_INDEX_CJK_SYMBOLS_AND_PUNCTUATION             = 48;
+  BL_FONT_UC_INDEX_HIRAGANA                                = 49;
+  BL_FONT_UC_INDEX_KATAKANA                                = 50;
+  BL_FONT_UC_INDEX_BOPOMOFO                                = 51;
+  BL_FONT_UC_INDEX_HANGUL_COMPATIBILITY_JAMO               = 52;
+  BL_FONT_UC_INDEX_PHAGS_PA                                = 53;
+  BL_FONT_UC_INDEX_ENCLOSED_CJK_LETTERS_AND_MONTHS         = 54;
+  BL_FONT_UC_INDEX_CJK_COMPATIBILITY                       = 55;
+  BL_FONT_UC_INDEX_HANGUL_SYLLABLES                        = 56;
+  BL_FONT_UC_INDEX_NON_PLANE                               = 57;
+  BL_FONT_UC_INDEX_PHOENICIAN                              = 58;
+  BL_FONT_UC_INDEX_CJK_UNIFIED_IDEOGRAPHS                  = 59;
+  BL_FONT_UC_INDEX_PRIVATE_USE_PLANE0                      = 60;
+  BL_FONT_UC_INDEX_CJK_STROKES                             = 61;
+  BL_FONT_UC_INDEX_ALPHABETIC_PRESENTATION_FORMS           = 62;
+  BL_FONT_UC_INDEX_ARABIC_PRESENTATION_FORMS_A             = 63;
+  BL_FONT_UC_INDEX_COMBINING_HALF_MARKS                    = 64;
+  BL_FONT_UC_INDEX_VERTICAL_FORMS                          = 65;
+  BL_FONT_UC_INDEX_SMALL_FORM_VARIANTS                     = 66;
+  BL_FONT_UC_INDEX_ARABIC_PRESENTATION_FORMS_B             = 67;
+  BL_FONT_UC_INDEX_HALFWIDTH_AND_FULLWIDTH_FORMS           = 68;
+  BL_FONT_UC_INDEX_SPECIALS                                = 69;
+  BL_FONT_UC_INDEX_TIBETAN                                 = 70;
+  BL_FONT_UC_INDEX_SYRIAC                                  = 71;
+  BL_FONT_UC_INDEX_THAANA                                  = 72;
+  BL_FONT_UC_INDEX_SINHALA                                 = 73;
+  BL_FONT_UC_INDEX_MYANMAR                                 = 74;
+  BL_FONT_UC_INDEX_ETHIOPIC                                = 75;
+  BL_FONT_UC_INDEX_CHEROKEE                                = 76;
+  BL_FONT_UC_INDEX_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS   = 77;
+  BL_FONT_UC_INDEX_OGHAM                                   = 78;
+  BL_FONT_UC_INDEX_RUNIC                                   = 79;
+  BL_FONT_UC_INDEX_KHMER                                   = 80;
+  BL_FONT_UC_INDEX_MONGOLIAN                               = 81;
+  BL_FONT_UC_INDEX_BRAILLE_PATTERNS                        = 82;
+  BL_FONT_UC_INDEX_YI_SYLLABLES_AND_RADICALS               = 83;
+  BL_FONT_UC_INDEX_TAGALOG_HANUNOO_BUHID_TAGBANWA          = 84;
+  BL_FONT_UC_INDEX_OLD_ITALIC                              = 85;
+  BL_FONT_UC_INDEX_GOTHIC                                  = 86;
+  BL_FONT_UC_INDEX_DESERET                                 = 87;
+  BL_FONT_UC_INDEX_MUSICAL_SYMBOLS                         = 88;
+  BL_FONT_UC_INDEX_MATHEMATICAL_ALPHANUMERIC_SYMBOLS       = 89;
+  BL_FONT_UC_INDEX_PRIVATE_USE_PLANE_15_16                 = 90;
+  BL_FONT_UC_INDEX_VARIATION_SELECTORS                     = 91;
+  BL_FONT_UC_INDEX_TAGS                                    = 92;
+  BL_FONT_UC_INDEX_LIMBU                                   = 93;
+  BL_FONT_UC_INDEX_TAI_LE                                  = 94;
+  BL_FONT_UC_INDEX_NEW_TAI_LUE                             = 95;
+  BL_FONT_UC_INDEX_BUGINESE                                = 96;
+  BL_FONT_UC_INDEX_GLAGOLITIC                              = 97;
+  BL_FONT_UC_INDEX_TIFINAGH                                = 98;
+  BL_FONT_UC_INDEX_YIJING_HEXAGRAM_SYMBOLS                 = 99;
+  BL_FONT_UC_INDEX_SYLOTI_NAGRI                            = 100;
+  BL_FONT_UC_INDEX_LINEAR_B_SYLLABARY_AND_IDEOGRAMS        = 101;
+  BL_FONT_UC_INDEX_ANCIENT_GREEK_NUMBERS                   = 102;
+  BL_FONT_UC_INDEX_UGARITIC                                = 103;
+  BL_FONT_UC_INDEX_OLD_PERSIAN                             = 104;
+  BL_FONT_UC_INDEX_SHAVIAN                                 = 105;
+  BL_FONT_UC_INDEX_OSMANYA                                 = 106;
+  BL_FONT_UC_INDEX_CYPRIOT_SYLLABARY                       = 107;
+  BL_FONT_UC_INDEX_KHAROSHTHI                              = 108;
+  BL_FONT_UC_INDEX_TAI_XUAN_JING_SYMBOLS                   = 109;
+  BL_FONT_UC_INDEX_CUNEIFORM                               = 110;
+  BL_FONT_UC_INDEX_COUNTING_ROD_NUMERALS                   = 111;
+  BL_FONT_UC_INDEX_SUNDANESE                               = 112;
+  BL_FONT_UC_INDEX_LEPCHA                                  = 113;
+  BL_FONT_UC_INDEX_OL_CHIKI                                = 114;
+  BL_FONT_UC_INDEX_SAURASHTRA                              = 115;
+  BL_FONT_UC_INDEX_KAYAH_LI                                = 116;
+  BL_FONT_UC_INDEX_REJANG                                  = 117;
+  BL_FONT_UC_INDEX_CHAM                                    = 118;
+  BL_FONT_UC_INDEX_ANCIENT_SYMBOLS                         = 119;
+  BL_FONT_UC_INDEX_PHAISTOS_DISC                           = 120;
+  BL_FONT_UC_INDEX_CARIAN_LYCIAN_LYDIAN                    = 121;
+  BL_FONT_UC_INDEX_DOMINO_AND_MAHJONG_TILES                = 122;
+  BL_FONT_UC_INDEX_INTERNAL_USAGE_123                      = 123;
+  BL_FONT_UC_INDEX_INTERNAL_USAGE_124                      = 124;
+  BL_FONT_UC_INDEX_INTERNAL_USAGE_125                      = 125;
+  BL_FONT_UC_INDEX_INTERNAL_USAGE_126                      = 126;
+  BL_FONT_UC_INDEX_INTERNAL_USAGE_127                      = 127;
+
+type
+  BLFontWeight = Integer;
+
+const
+  BL_FONT_WEIGHT_THIN        = 100;
+  BL_FONT_WEIGHT_EXTRA_LIGHT = 200;
+  BL_FONT_WEIGHT_LIGHT       = 300;
+  BL_FONT_WEIGHT_SEMI_LIGHT  = 350;
+  BL_FONT_WEIGHT_NORMAL      = 400;
+  BL_FONT_WEIGHT_MEDIUM      = 500;
+  BL_FONT_WEIGHT_SEMI_BOLD   = 600;
+  BL_FONT_WEIGHT_BOLD        = 700;
+  BL_FONT_WEIGHT_EXTRA_BOLD  = 800;
+  BL_FONT_WEIGHT_BLACK       = 900;
+  BL_FONT_WEIGHT_EXTRA_BLACK = 950;
+
+type
+  BLFormat = Integer;
+
+const
+  BL_FORMAT_NONE           = 0;
+  BL_FORMAT_PRGB32         = 1;
+  BL_FORMAT_XRGB32         = 2;
+  BL_FORMAT_A8             = 3;
+  BL_FORMAT_COUNT          = 4;
+  BL_FORMAT_RESERVED_COUNT = 16;
+
+type
+  BLFormatFlags = Integer;
+
+const
+  BL_FORMAT_FLAG_RGB            = 1;
+  BL_FORMAT_FLAG_ALPHA          = 2;
+  BL_FORMAT_FLAG_RGBA           = 3;
+  BL_FORMAT_FLAG_LUM            = 4;
+  BL_FORMAT_FLAG_LUMA           = 6;
+  BL_FORMAT_FLAG_INDEXED        = 16;
+  BL_FORMAT_FLAG_PREMULTIPLIED  = 256;
+  BL_FORMAT_FLAG_BYTE_SWAP      = 512;
+  BL_FORMAT_FLAG_BYTE_ALIGNED   = 65536;
+  BL_FORMAT_FLAG_UNDEFINED_BITS = 131072;
+  BL_FORMAT_FLAG_LE             = 0;
+  BL_FORMAT_FLAG_BE             = 512;
+
+type
+  BLGeometryDirection = Integer;
+
+const
+  BL_GEOMETRY_DIRECTION_NONE = 0;
+  BL_GEOMETRY_DIRECTION_CW   = 1;
+  BL_GEOMETRY_DIRECTION_CCW  = 2;
+
+type
+  BLGeometryType = Integer;
+
+const
+  BL_GEOMETRY_TYPE_NONE             = 0;
+  BL_GEOMETRY_TYPE_BOXI             = 1;
+  BL_GEOMETRY_TYPE_BOXD             = 2;
+  BL_GEOMETRY_TYPE_RECTI            = 3;
+  BL_GEOMETRY_TYPE_RECTD            = 4;
+  BL_GEOMETRY_TYPE_CIRCLE           = 5;
+  BL_GEOMETRY_TYPE_ELLIPSE          = 6;
+  BL_GEOMETRY_TYPE_ROUND_RECT       = 7;
+  BL_GEOMETRY_TYPE_ARC              = 8;
+  BL_GEOMETRY_TYPE_CHORD            = 9;
+  BL_GEOMETRY_TYPE_PIE              = 10;
+  BL_GEOMETRY_TYPE_LINE             = 11;
+  BL_GEOMETRY_TYPE_TRIANGLE         = 12;
+  BL_GEOMETRY_TYPE_POLYLINEI        = 13;
+  BL_GEOMETRY_TYPE_POLYLINED        = 14;
+  BL_GEOMETRY_TYPE_POLYGONI         = 15;
+  BL_GEOMETRY_TYPE_POLYGOND         = 16;
+  BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI  = 17;
+  BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD  = 18;
+  BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI = 19;
+  BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD = 20;
+  BL_GEOMETRY_TYPE_PATH             = 21;
+  BL_GEOMETRY_TYPE_REGION           = 22;
+  BL_GEOMETRY_TYPE_COUNT            = 23;
+
+type
+  BLGlyphPlacementType = Integer;
+
+const
+  BL_GLYPH_PLACEMENT_TYPE_NONE           = 0;
+  BL_GLYPH_PLACEMENT_TYPE_ADVANCE_OFFSET = 1;
+  BL_GLYPH_PLACEMENT_TYPE_DESIGN_UNITS   = 2;
+  BL_GLYPH_PLACEMENT_TYPE_USER_UNITS     = 3;
+  BL_GLYPH_PLACEMENT_TYPE_ABSOLUTE_UNITS = 4;
+
+type
+  BLGlyphRunFlags = Integer;
+
+const
+  BL_GLYPH_RUN_FLAG_UCS4_CONTENT      = $10000000;
+  BL_GLYPH_RUN_FLAG_INVALID_TEXT      = $20000000;
+  BL_GLYPH_RUN_FLAG_UNDEFINED_GLYPHS  = $40000000;
+  BL_GLYPH_RUN_FLAG_INVALID_FONT_DATA = $80000000;
+
+type
+  BLGradientQuality = Integer;
+
+const
+  BL_GRADIENT_QUALITY_NEAREST = 0;
+  BL_GRADIENT_QUALITY_COUNT   = 1;
+
+type
+  BLGradientType = Integer;
+
+const
+  BL_GRADIENT_TYPE_LINEAR  = 0;
+  BL_GRADIENT_TYPE_RADIAL  = 1;
+  BL_GRADIENT_TYPE_CONICAL = 2;
+  BL_GRADIENT_TYPE_COUNT   = 3;
+
+type
+  BLGradientValue = Integer;
+
+const
+  BL_GRADIENT_VALUE_COMMON_X0     = 0;
+  BL_GRADIENT_VALUE_COMMON_Y0     = 1;
+  BL_GRADIENT_VALUE_COMMON_X1     = 2;
+  BL_GRADIENT_VALUE_COMMON_Y1     = 3;
+  BL_GRADIENT_VALUE_RADIAL_R0     = 4;
+  BL_GRADIENT_VALUE_CONICAL_ANGLE = 2;
+  BL_GRADIENT_VALUE_COUNT         = 6;
+
+type
+  BLHitTest = Integer;
+
+const
+  BL_HIT_TEST_IN      = 0;
+  BL_HIT_TEST_PART    = 1;
+  BL_HIT_TEST_OUT     = 2;
+  BL_HIT_TEST_INVALID = -1;
+
+type
+  BLImageInfoFlags = Integer;
+
+const
+  BL_IMAGE_INFO_FLAG_PROGRESSIVE = 1;
+
+type
+  BLImageScaleFilter = Integer;
+
+const
+  BL_IMAGE_SCALE_FILTER_NONE     = 0;
+  BL_IMAGE_SCALE_FILTER_NEAREST  = 1;
+  BL_IMAGE_SCALE_FILTER_BILINEAR = 2;
+  BL_IMAGE_SCALE_FILTER_BICUBIC  = 3;
+  BL_IMAGE_SCALE_FILTER_BELL     = 4;
+  BL_IMAGE_SCALE_FILTER_GAUSS    = 5;
+  BL_IMAGE_SCALE_FILTER_HERMITE  = 6;
+  BL_IMAGE_SCALE_FILTER_HANNING  = 7;
+  BL_IMAGE_SCALE_FILTER_CATROM   = 8;
+  BL_IMAGE_SCALE_FILTER_BESSEL   = 9;
+  BL_IMAGE_SCALE_FILTER_SINC     = 10;
+  BL_IMAGE_SCALE_FILTER_LANCZOS  = 11;
+  BL_IMAGE_SCALE_FILTER_BLACKMAN = 12;
+  BL_IMAGE_SCALE_FILTER_MITCHELL = 13;
+  BL_IMAGE_SCALE_FILTER_USER     = 14;
+  BL_IMAGE_SCALE_FILTER_COUNT    = 15;
+
+type
+  BLImplTraits = Integer;
+
+const
+  BL_IMPL_TRAIT_MUTABLE   = 1;
+  BL_IMPL_TRAIT_IMMUTABLE = 2;
+  BL_IMPL_TRAIT_EXTERNAL  = 4;
+  BL_IMPL_TRAIT_FOREIGN   = 8;
+  BL_IMPL_TRAIT_VIRT      = 16;
+  BL_IMPL_TRAIT_NULL      = 128;
+
+type
+  BLImplType = Integer;
+
+const
+  BL_IMPL_TYPE_NULL                   = 0;
+  BL_IMPL_TYPE_ARRAY_VAR              = 1;
+  BL_IMPL_TYPE_ARRAY_I8               = 2;
+  BL_IMPL_TYPE_ARRAY_U8               = 3;
+  BL_IMPL_TYPE_ARRAY_I16              = 4;
+  BL_IMPL_TYPE_ARRAY_U16              = 5;
+  BL_IMPL_TYPE_ARRAY_I32              = 6;
+  BL_IMPL_TYPE_ARRAY_U32              = 7;
+  BL_IMPL_TYPE_ARRAY_I64              = 8;
+  BL_IMPL_TYPE_ARRAY_U64              = 9;
+  BL_IMPL_TYPE_ARRAY_F32              = 10;
+  BL_IMPL_TYPE_ARRAY_F64              = 11;
+  BL_IMPL_TYPE_ARRAY_STRUCT_1         = 12;
+  BL_IMPL_TYPE_ARRAY_STRUCT_2         = 13;
+  BL_IMPL_TYPE_ARRAY_STRUCT_3         = 14;
+  BL_IMPL_TYPE_ARRAY_STRUCT_4         = 15;
+  BL_IMPL_TYPE_ARRAY_STRUCT_6         = 16;
+  BL_IMPL_TYPE_ARRAY_STRUCT_8         = 17;
+  BL_IMPL_TYPE_ARRAY_STRUCT_10        = 18;
+  BL_IMPL_TYPE_ARRAY_STRUCT_12        = 19;
+  BL_IMPL_TYPE_ARRAY_STRUCT_16        = 20;
+  BL_IMPL_TYPE_ARRAY_STRUCT_20        = 21;
+  BL_IMPL_TYPE_ARRAY_STRUCT_24        = 22;
+  BL_IMPL_TYPE_ARRAY_STRUCT_32        = 23;
+  BL_IMPL_TYPE_BIT_ARRAY              = 32;
+  BL_IMPL_TYPE_BIT_SET                = 33;
+  BL_IMPL_TYPE_STRING                 = 39;
+  BL_IMPL_TYPE_PATH                   = 40;
+  BL_IMPL_TYPE_REGION                 = 43;
+  BL_IMPL_TYPE_IMAGE                  = 44;
+  BL_IMPL_TYPE_IMAGE_CODEC            = 45;
+  BL_IMPL_TYPE_IMAGE_DECODER          = 46;
+  BL_IMPL_TYPE_IMAGE_ENCODER          = 47;
+  BL_IMPL_TYPE_GRADIENT               = 48;
+  BL_IMPL_TYPE_PATTERN                = 49;
+  BL_IMPL_TYPE_CONTEXT                = 55;
+  BL_IMPL_TYPE_FONT                   = 56;
+  BL_IMPL_TYPE_FONT_FACE              = 57;
+  BL_IMPL_TYPE_FONT_DATA              = 58;
+  BL_IMPL_TYPE_FONT_MANAGER           = 59;
+  BL_IMPL_TYPE_FONT_FEATURE_OPTIONS   = 60;
+  BL_IMPL_TYPE_FONT_VARIATION_OPTIONS = 61;
+  BL_IMPL_TYPE_COUNT                  = 64;
+
+type
+  BLMatrix2DOp = Integer;
+
+const
+  BL_MATRIX2D_OP_RESET          = 0;
+  BL_MATRIX2D_OP_ASSIGN         = 1;
+  BL_MATRIX2D_OP_TRANSLATE      = 2;
+  BL_MATRIX2D_OP_SCALE          = 3;
+  BL_MATRIX2D_OP_SKEW           = 4;
+  BL_MATRIX2D_OP_ROTATE         = 5;
+  BL_MATRIX2D_OP_ROTATE_PT      = 6;
+  BL_MATRIX2D_OP_TRANSFORM      = 7;
+  BL_MATRIX2D_OP_POST_TRANSLATE = 8;
+  BL_MATRIX2D_OP_POST_SCALE     = 9;
+  BL_MATRIX2D_OP_POST_SKEW      = 10;
+  BL_MATRIX2D_OP_POST_ROTATE    = 11;
+  BL_MATRIX2D_OP_POST_ROTATE_PT = 12;
+  BL_MATRIX2D_OP_POST_TRANSFORM = 13;
+  BL_MATRIX2D_OP_COUNT          = 14;
+
+type
+  BLMatrix2DType = Integer;
+
+const
+  BL_MATRIX2D_TYPE_IDENTITY  = 0;
+  BL_MATRIX2D_TYPE_TRANSLATE = 1;
+  BL_MATRIX2D_TYPE_SCALE     = 2;
+  BL_MATRIX2D_TYPE_SWAP      = 3;
+  BL_MATRIX2D_TYPE_AFFINE    = 4;
+  BL_MATRIX2D_TYPE_INVALID   = 5;
+  BL_MATRIX2D_TYPE_COUNT     = 6;
+
+type
+  BLMatrix2DValue = Integer;
+
+const
+  BL_MATRIX2D_VALUE_00    = 0;
+  BL_MATRIX2D_VALUE_01    = 1;
+  BL_MATRIX2D_VALUE_10    = 2;
+  BL_MATRIX2D_VALUE_11    = 3;
+  BL_MATRIX2D_VALUE_20    = 4;
+  BL_MATRIX2D_VALUE_21    = 5;
+  BL_MATRIX2D_VALUE_COUNT = 6;
+
+type
+  BLModifyOp = Integer;
+
+const
+  BL_MODIFY_OP_ASSIGN_FIT  = 0;
+  BL_MODIFY_OP_ASSIGN_GROW = 1;
+  BL_MODIFY_OP_APPEND_FIT  = 2;
+  BL_MODIFY_OP_APPEND_GROW = 3;
+  BL_MODIFY_OP_COUNT       = 4;
+
+type
+  BLOffsetMode = Integer;
+
+const
+  BL_OFFSET_MODE_DEFAULT   = 0;
+  BL_OFFSET_MODE_ITERATIVE = 1;
+
+type
+  BLPathCmd = Integer;
+
+const
+  BL_PATH_CMD_MOVE  = 0;
+  BL_PATH_CMD_ON    = 1;
+  BL_PATH_CMD_QUAD  = 2;
+  BL_PATH_CMD_CUBIC = 3;
+  BL_PATH_CMD_CLOSE = 4;
+  BL_PATH_CMD_COUNT = 5;
+
+type
+  BLPathCmdExtra = Integer;
+
+const
+  BL_PATH_CMD_PRESERVE = $FFFFFFFF;
+
+type
+  BLPathFlags = Integer;
+
+const
+  BL_PATH_FLAG_EMPTY    = $1;
+  BL_PATH_FLAG_MULTIPLE = $2;
+  BL_PATH_FLAG_QUADS    = $4;
+  BL_PATH_FLAG_CUBICS   = $8;
+  BL_PATH_FLAG_INVALID  = $40000000;
+  BL_PATH_FLAG_DIRTY    = $80000000;
+
+type
+  BLPathReverseMode = Integer;
+
+const
+  BL_PATH_REVERSE_MODE_COMPLETE = 0;
+  BL_PATH_REVERSE_MODE_SEPARATE = 1;
+  BL_PATH_REVERSE_MODE_COUNT    = 2;
+
+type
+  BLPatternQuality = Integer;
+
+const
+  BL_PATTERN_QUALITY_NEAREST  = 0;
+  BL_PATTERN_QUALITY_BILINEAR = 1;
+  BL_PATTERN_QUALITY_COUNT    = 2;
+
+type
+  BLPixelConverterCreateFlags = Integer;
+
+const
+  BL_PIXEL_CONVERTER_CREATE_FLAG_DONT_COPY_PALETTE = 1;
+  BL_PIXEL_CONVERTER_CREATE_FLAG_ALTERABLE_PALETTE = 2;
+  BL_PIXEL_CONVERTER_CREATE_FLAG_NO_MULTI_STEP     = 4;
+
+type
+  BLRegionType = Integer;
+
+const
+  BL_REGION_TYPE_EMPTY   = 0;
+  BL_REGION_TYPE_RECT    = 1;
+  BL_REGION_TYPE_COMPLEX = 2;
+  BL_REGION_TYPE_COUNT   = 3;
+
+type
+  BLRenderingQuality = Integer;
+
+const
+  BL_RENDERING_QUALITY_ANTIALIAS = 0;
+  BL_RENDERING_QUALITY_COUNT     = 1;
+
+type
+  BLResultCode = Integer;
+
+const
+  BL_SUCCESS                            = 0;
+  BL_ERROR_START_INDEX                  = 65536;
+  BL_ERROR_OUT_OF_MEMORY                = 65536;
+  BL_ERROR_INVALID_VALUE                = 65537;
+  BL_ERROR_INVALID_STATE                = 65538;
+  BL_ERROR_INVALID_HANDLE               = 65539;
+  BL_ERROR_VALUE_TOO_LARGE              = 65540;
+  BL_ERROR_NOT_INITIALIZED              = 65541;
+  BL_ERROR_NOT_IMPLEMENTED              = 65542;
+  BL_ERROR_NOT_PERMITTED                = 65543;
+  BL_ERROR_IO                           = 65544;
+  BL_ERROR_BUSY                         = 65545;
+  BL_ERROR_INTERRUPTED                  = 65546;
+  BL_ERROR_TRY_AGAIN                    = 65547;
+  BL_ERROR_TIMED_OUT                    = 65548;
+  BL_ERROR_BROKEN_PIPE                  = 65549;
+  BL_ERROR_INVALID_SEEK                 = 65550;
+  BL_ERROR_SYMLINK_LOOP                 = 65551;
+  BL_ERROR_FILE_TOO_LARGE               = 65552;
+  BL_ERROR_ALREADY_EXISTS               = 65553;
+  BL_ERROR_ACCESS_DENIED                = 65554;
+  BL_ERROR_MEDIA_CHANGED                = 65555;
+  BL_ERROR_READ_ONLY_FS                 = 65556;
+  BL_ERROR_NO_DEVICE                    = 65557;
+  BL_ERROR_NO_ENTRY                     = 65558;
+  BL_ERROR_NO_MEDIA                     = 65559;
+  BL_ERROR_NO_MORE_DATA                 = 65560;
+  BL_ERROR_NO_MORE_FILES                = 65561;
+  BL_ERROR_NO_SPACE_LEFT                = 65562;
+  BL_ERROR_NOT_EMPTY                    = 65563;
+  BL_ERROR_NOT_FILE                     = 65564;
+  BL_ERROR_NOT_DIRECTORY                = 65565;
+  BL_ERROR_NOT_SAME_DEVICE              = 65566;
+  BL_ERROR_NOT_BLOCK_DEVICE             = 65567;
+  BL_ERROR_INVALID_FILE_NAME            = 65568;
+  BL_ERROR_FILE_NAME_TOO_LONG           = 65569;
+  BL_ERROR_TOO_MANY_OPEN_FILES          = 65570;
+  BL_ERROR_TOO_MANY_OPEN_FILES_BY_OS    = 65571;
+  BL_ERROR_TOO_MANY_LINKS               = 65572;
+  BL_ERROR_TOO_MANY_THREADS             = 65573;
+  BL_ERROR_THREAD_POOL_EXHAUSTED        = 65574;
+  BL_ERROR_FILE_EMPTY                   = 65575;
+  BL_ERROR_OPEN_FAILED                  = 65576;
+  BL_ERROR_NOT_ROOT_DEVICE              = 65577;
+  BL_ERROR_UNKNOWN_SYSTEM_ERROR         = 65578;
+  BL_ERROR_INVALID_ALIGNMENT            = 65579;
+  BL_ERROR_INVALID_SIGNATURE            = 65580;
+  BL_ERROR_INVALID_DATA                 = 65581;
+  BL_ERROR_INVALID_STRING               = 65582;
+  BL_ERROR_DATA_TRUNCATED               = 65583;
+  BL_ERROR_DATA_TOO_LARGE               = 65584;
+  BL_ERROR_DECOMPRESSION_FAILED         = 65585;
+  BL_ERROR_INVALID_GEOMETRY             = 65586;
+  BL_ERROR_NO_MATCHING_VERTEX           = 65587;
+  BL_ERROR_NO_MATCHING_COOKIE           = 65588;
+  BL_ERROR_NO_STATES_TO_RESTORE         = 65589;
+  BL_ERROR_IMAGE_TOO_LARGE              = 65590;
+  BL_ERROR_IMAGE_NO_MATCHING_CODEC      = 65591;
+  BL_ERROR_IMAGE_UNKNOWN_FILE_FORMAT    = 65592;
+  BL_ERROR_IMAGE_DECODER_NOT_PROVIDED   = 65593;
+  BL_ERROR_IMAGE_ENCODER_NOT_PROVIDED   = 65594;
+  BL_ERROR_PNG_MULTIPLE_IHDR            = 65595;
+  BL_ERROR_PNG_INVALID_IDAT             = 65596;
+  BL_ERROR_PNG_INVALID_IEND             = 65597;
+  BL_ERROR_PNG_INVALID_PLTE             = 65598;
+  BL_ERROR_PNG_INVALID_TRNS             = 65599;
+  BL_ERROR_PNG_INVALID_FILTER           = 65600;
+  BL_ERROR_JPEG_UNSUPPORTED_FEATURE     = 65601;
+  BL_ERROR_JPEG_INVALID_SOS             = 65602;
+  BL_ERROR_JPEG_INVALID_SOF             = 65603;
+  BL_ERROR_JPEG_MULTIPLE_SOF            = 65604;
+  BL_ERROR_JPEG_UNSUPPORTED_SOF         = 65605;
+  BL_ERROR_FONT_NOT_INITIALIZED         = 65606;
+  BL_ERROR_FONT_NO_MATCH                = 65607;
+  BL_ERROR_FONT_NO_CHARACTER_MAPPING    = 65608;
+  BL_ERROR_FONT_MISSING_IMPORTANT_TABLE = 65609;
+  BL_ERROR_FONT_FEATURE_NOT_AVAILABLE   = 65610;
+  BL_ERROR_FONT_CFF_INVALID_DATA        = 65611;
+  BL_ERROR_FONT_PROGRAM_TERMINATED      = 65612;
+  BL_ERROR_INVALID_GLYPH                = 65613;
+
+type
+  BLRuntimeLimits = Integer;
+
+const
+  BL_RUNTIME_MAX_IMAGE_SIZE   = 65535;
+  BL_RUNTIME_MAX_THREAD_COUNT = 32;
+
+type
+  BLRuntimeInfoType = Integer;
+
+const
+  BL_RUNTIME_INFO_TYPE_BUILD    = 0;
+  BL_RUNTIME_INFO_TYPE_SYSTEM   = 1;
+  BL_RUNTIME_INFO_TYPE_RESOURCE = 2;
+  BL_RUNTIME_INFO_TYPE_COUNT    = 3;
+
+type
+  BLRuntimeBuildType = Integer;
+
+const
+  BL_RUNTIME_BUILD_TYPE_DEBUG   = 0;
+  BL_RUNTIME_BUILD_TYPE_RELEASE = 1;
+
+type
+  BLRuntimeCpuArch = Integer;
+
+const
+  BL_RUNTIME_CPU_ARCH_UNKNOWN = 0;
+  BL_RUNTIME_CPU_ARCH_X86     = 1;
+  BL_RUNTIME_CPU_ARCH_ARM     = 2;
+  BL_RUNTIME_CPU_ARCH_MIPS    = 3;
+
+type
+  BLRuntimeCpuFeatures = Integer;
+
+const
+  BL_RUNTIME_CPU_FEATURE_X86_SSE2   = 1;
+  BL_RUNTIME_CPU_FEATURE_X86_SSE3   = 2;
+  BL_RUNTIME_CPU_FEATURE_X86_SSSE3  = 4;
+  BL_RUNTIME_CPU_FEATURE_X86_SSE4_1 = 8;
+  BL_RUNTIME_CPU_FEATURE_X86_SSE4_2 = 16;
+  BL_RUNTIME_CPU_FEATURE_X86_AVX    = 32;
+  BL_RUNTIME_CPU_FEATURE_X86_AVX2   = 64;
+
+type
+  BLRuntimeCleanupFlags = Integer;
+
+const
+  BL_RUNTIME_CLEANUP_OBJECT_POOL = 1;
+  BL_RUNTIME_CLEANUP_ZEROED_POOL = 2;
+  BL_RUNTIME_CLEANUP_THREAD_POOL = 16;
+  BL_RUNTIME_CLEANUP_EVERYTHING  = $FFFFFFFF;
+
+type
+  BLStrokeCap = Integer;
+
+const
+  BL_STROKE_CAP_BUTT         = 0;
+  BL_STROKE_CAP_SQUARE       = 1;
+  BL_STROKE_CAP_ROUND        = 2;
+  BL_STROKE_CAP_ROUND_REV    = 3;
+  BL_STROKE_CAP_TRIANGLE     = 4;
+  BL_STROKE_CAP_TRIANGLE_REV = 5;
+  BL_STROKE_CAP_COUNT        = 6;
+
+type
+  BLStrokeCapPosition = Integer;
+
+const
+  BL_STROKE_CAP_POSITION_START = 0;
+  BL_STROKE_CAP_POSITION_END   = 1;
+  BL_STROKE_CAP_POSITION_COUNT = 2;
+
+type
+  BLStrokeJoin = Integer;
+
+const
+  BL_STROKE_JOIN_MITER_CLIP  = 0;
+  BL_STROKE_JOIN_MITER_BEVEL = 1;
+  BL_STROKE_JOIN_MITER_ROUND = 2;
+  BL_STROKE_JOIN_BEVEL       = 3;
+  BL_STROKE_JOIN_ROUND       = 4;
+  BL_STROKE_JOIN_COUNT       = 5;
+
+type
+  BLStrokeTransformOrder = Integer;
+
+const
+  BL_STROKE_TRANSFORM_ORDER_AFTER  = 0;
+  BL_STROKE_TRANSFORM_ORDER_BEFORE = 1;
+  BL_STROKE_TRANSFORM_ORDER_COUNT  = 2;
+
+type
+  BLStyleType = Integer;
+
+const
+  BL_STYLE_TYPE_NONE     = 0;
+  BL_STYLE_TYPE_SOLID    = 1;
+  BL_STYLE_TYPE_PATTERN  = 2;
+  BL_STYLE_TYPE_GRADIENT = 3;
+  BL_STYLE_TYPE_COUNT    = 4;
+
+type
+  BLTextDirection = Integer;
+
+const
+  BL_TEXT_DIRECTION_LTR   = 0;
+  BL_TEXT_DIRECTION_RTL   = 1;
+  BL_TEXT_DIRECTION_COUNT = 2;
+
+type
+  BLTextEncoding = Integer;
+
+const
+  BL_TEXT_ENCODING_UTF8   = 0;
+  BL_TEXT_ENCODING_UTF16  = 1;
+  BL_TEXT_ENCODING_UTF32  = 2;
+  BL_TEXT_ENCODING_LATIN1 = 3;
+  BL_TEXT_ENCODING_WCHAR  = 1;
+  BL_TEXT_ENCODING_COUNT  = 4;
+
+type
+  BLTextOrientation = Integer;
+
+const
+  BL_TEXT_ORIENTATION_HORIZONTAL = 0;
+  BL_TEXT_ORIENTATION_VERTICAL   = 1;
+  BL_TEXT_ORIENTATION_COUNT      = 2;
+
+type
+  BLApproximationOptions = record
+    flattenMode: UInt8;
+    offsetMode: UInt8;
+    reservedFlags: array [0..5] of UInt8;
+    flattenTolerance: Double;
+    simplifyTolerance: Double;
+    offsetParameter: Double;
+  end;
+  _PBLApproximationOptions = ^BLApproximationOptions;
+
+type
+  BLRgba32 = packed record
+  case Integer of
+    0: (value: UInt32);
+    1: (b: UInt8;
+        g: UInt8;
+        r: UInt8;
+        a: UInt8);
+  end;
+  _PBLRgba32 = ^BLRgba32;
+
+type
+  BLRgba64 = packed record
+  case Integer of
+    0: (value: UInt64);
+    1: (b: UInt16;
+        g: UInt16;
+        r: UInt16;
+        a: UInt16);
+  end;
+
+type
+  BLRgba = record
+    r: Single;
+    g: Single;
+    b: Single;
+    a: Single;
+  end;
+  _PBLRgba = ^BLRgba;
+
+type
+  BLArrayView = record
+    data: Pointer;
+    size: NativeUInt;
+  end;
+
+type
+  BLArc = record
+    cx: Double;
+    cy: Double;
+    rx: Double;
+    ry: Double;
+    start: Double;
+    sweep: Double;
+  end;
+
+type
+  BLCircle = record
+    cx: Double;
+    cy: Double;
+    r: Double;
+  end;
+
+type
+  BLEllipse = record
+    cx: Double;
+    cy: Double;
+    rx: Double;
+    ry: Double;
+  end;
+
+type
+  BLLine = record
+    x0: Double;
+    y0: Double;
+    x1: Double;
+    y1: Double;
+  end;
+
+type
+  BLPoint = record
+    x: Double;
+    y: Double;
+  end;
+  _PBLPoint = ^BLPoint;
+
+type
+  BLPointI = record
+    x: Integer;
+    y: Integer;
+  end;
+  _PBLPointI = ^BLPointI;
+
+type
+  BLSize = record
+    w: Double;
+    h: Double;
+  end;
+  _PBLSize = ^BLSize;
+
+type
+  BLSizeI = record
+    w: Integer;
+    h: Integer;
+  end;
+  _PBLSizeI = ^BLSizeI;
+
+type
+  BLRect = record
+    x: Double;
+    y: Double;
+    w: Double;
+    h: Double;
+  end;
+  _PBLRect = ^BLRect;
+
+type
+  BLRectI = record
+    x: Integer;
+    y: Integer;
+    w: Integer;
+    h: Integer;
+  end;
+  _PBLRectI = ^BLRectI;
+
+type
+  BLRoundRect = record
+    x: Double;
+    y: Double;
+    w: Double;
+    h: Double;
+    rx: Double;
+    ry: Double;
+  end;
+
+type
+  BLTriangle = record
+    x0: Double;
+    y0: Double;
+    x1: Double;
+    y1: Double;
+    x2: Double;
+    y2: Double;
+  end;
+
+type
+  BLBox = record
+    x0: Double;
+    y0: Double;
+    x1: Double;
+    y1: Double;
+  end;
+  _PBLBox = ^BLBox;
+
+type
+  BLBoxI = record
+    x0: Integer;
+    y0: Integer;
+    x1: Integer;
+    y1: Integer;
+  end;
+  _PBLBoxI = ^BLBoxI;
+
+type
+  BLMatrix2D = record
+  case Integer of
+    0: (m: array [0..5] of Double);
+    1: (m00: Double;
+        m01: Double;
+        m10: Double;
+        m11: Double;
+        m20: Double;
+        m21: Double);
+  end;
+  _PBLMatrix2D = ^BLMatrix2D;
+
+type
+  BLDataView = BLArrayView;
+
+type
+  BLArrayImpl = record
+    capacity: NativeUInt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    itemSize: UInt8;
+    dispatchType: UInt8;
+    reserved: array [0..1] of UInt8;
+    case Integer of
+      0: (data: Pointer;
+          size: NativeUInt);
+      1: (view: BLDataView);
+  end;
+  PBLArrayImpl = ^BLArrayImpl;
+
+type
+  BLArrayCore = record
+    impl: PBLArrayImpl;
+  end;
+  PBLArrayCore = ^BLArrayCore;
+
+type
+  BLStrokeOptionsCore = record
+    options: record
+      case Integer of
+        0: (startCap: UInt8;
+            endCap: UInt8;
+            join: UInt8;
+            transformOrder: UInt8;
+            reserved: array [0..3] of UInt8);
+        1: (caps: array [0..1] of UInt8);
+        2: (hints: UInt64);
+    end;
+    width: Double;
+    miterLimit: Double;
+    dashOffset: Double;
+    dashArray: BLArrayCore;
+  end;
+  PBLStrokeOptionsCore = ^BLStrokeOptionsCore;
+
+type
+  BLImageImpl = record
+    pixelData: Pointer;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    format: UInt8;
+    flags: UInt8;
+    depth: UInt16;
+    size: BLSizeI;
+    stride: IntPtr;
+  end;
+  _PBLImageImpl = ^BLImageImpl;
+
+type
+  BLImageCore = record
+    impl: _PBLImageImpl;
+  end;
+  PBLImageCore = ^BLImageCore;
+
+type
+  BLContextCookie = record
+    data: array [0..1] of UInt64;
+  end;
+  _PBLContextCookie = ^BLContextCookie;
+
+type
+  BLContextCreateInfo = record
+    flags: UInt32;
+    threadCount: Int32;
+    cpuFeatures: UInt32;
+    commandQueueLimit: Int32;
+    reserved: array [0..3] of UInt32;
+  end;
+  _PBLContextCreateInfo = ^BLContextCreateInfo;
+
+type
+  BLContextHints = record
+    case Integer of
+      0: (renderingQuality: UInt8;
+          gradientQuality: UInt8;
+          patternQuality: UInt8);
+      1: (hints: array [0..7] of UInt8);
+  end;
+  _PBLContextHints = ^BLContextHints;
+
+type
+  BLContextState = record
+    targetImage: PBLImageCore;
+    targetSize: BLSize;
+    hints: BLContextHints;
+    compOp: UInt8;
+    fillRule: UInt8;
+    styleType: array [0..1] of UInt8;
+    reserved: array [0..3] of UInt8;
+    approximationOptions: BLApproximationOptions;
+    globalAlpha: Double;
+    styleAlpha: array [0..1] of Double;
+    strokeOptions: BLStrokeOptionsCore;
+    metaMatrix: BLMatrix2D;
+    userMatrix: BLMatrix2D;
+    savedStateCount: NativeUInt;
+  end;
+  _PBLContextState = ^BLContextState;
+
+type
+  PBLContextVirt = Pointer;
+
+type
+  BLContextImpl = record
+    virt: PBLContextVirt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    contextType: UInt32;
+    state: _PBLContextState;
+  end;
+  PBLContextImpl = ^BLContextImpl;
+
+type
+  BLContextCore = record
+    impl: PBLContextImpl;
+  end;
+  PBLContextCore = ^BLContextCore;
+
+type
+  BLCreateForeignInfo = record
+    data: Pointer;
+    size: NativeUInt;
+    destroyFunc: BLDestroyImplFunc;
+    destroyData: Pointer;
+  end;
+
+type
+  BLStringView = record
+    data: PUTF8Char;
+    size: NativeUInt;
+  end;
+
+type
+  BLStringImpl = record
+    capacity: NativeUInt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    reserved: UInt32;
+    case Integer of
+      0: (data: PUTF8Char;
+          size: NativeUInt);
+      1: (view: BLStringView);
+  end;
+  _PBLStringImpl = ^BLStringImpl;
+
+type
+  BLStringCore = record
+    impl: _PBLStringImpl;
+  end;
+  PBLStringCore = ^BLStringCore;
+
+
+type
+  PBLFontDataVirt = Pointer;
+
+type
+  BLFontDataImpl = record
+    virt: PBLFontDataVirt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    faceType: UInt8;
+    reserved: array [0..2] of UInt8;
+    faceCount: UInt32;
+    flags: UInt32;
+  end;
+  _PBLFontDataImpl = ^BLFontDataImpl;
+
+type
+  BLFontDataCore = record
+    impl: _PBLFontDataImpl;
+  end;
+  PBLFontDataCore = ^BLFontDataCore;
+
+type
+  BLFontDesignMetrics = record
+    unitsPerEm: Integer;
+    lowestPPEM: Integer;
+    lineGap: Integer;
+    xHeight: Integer;
+    capHeight: Integer;
+    ascent: Integer;
+    vAscent: Integer;
+    descent: Integer;
+    vDescent: Integer;
+    hMinLSB: Integer;
+    vMinLSB: Integer;
+    hMinTSB: Integer;
+    vMinTSB: Integer;
+    hMaxAdvance: Integer;
+    vMaxAdvance: Integer;
+    glyphBoundingBox: BLBoxI;
+    underlinePosition: Integer;
+    underlineThickness: Integer;
+    strikethroughPosition: Integer;
+    strikethroughThickness: Integer;
+  end;
+  _PBLFontDesignMetrics = ^BLFontDesignMetrics;
+
+type
+  BLFontFaceInfo = record
+    faceType: UInt8;
+    outlineType: UInt8;
+    glyphCount: UInt16;
+    revision: UInt32;
+    faceIndex: Int32;
+    faceFlags: UInt32;
+    diagFlags: UInt32;
+    reserved: array [0..2] of UInt32;
+  end;
+  _PBLFontFaceInfo = ^BLFontFaceInfo;
+
+type
+  BLFontFeature = record
+    tag: BLTag;
+    value: UInt32;
+  end;
+
+type
+  BLFontUnicodeCoverage = record
+    data: array [0..3] of UInt32;
+  end;
+  _PBLFontUnicodeCoverage = ^BLFontUnicodeCoverage;
+
+type
+  BLFontPanose = record
+  case Integer of
+    0: (data: array [0..9] of UInt8);
+    1: (familyKind: UInt8);
+    2: (text: record
+          familyKind: UInt8;
+          serifStyle: UInt8;
+          weight: UInt8;
+          proportion: UInt8;
+          contrast: UInt8;
+          strokeVariation: UInt8;
+          armStyle: UInt8;
+          letterform: UInt8;
+          midline: UInt8;
+          xHeight: UInt8
+        end);
+    3: (script: record
+          familyKind: UInt8;
+          toolKind: UInt8;
+          weight: UInt8;
+          spacing: UInt8;
+          aspectRatio: UInt8;
+          contrast: UInt8;
+          topology: UInt8;
+          form: UInt8;
+          finials: UInt8;
+          xAscent: UInt8;
+        end);
+    4: (decorative: record
+          familyKind: UInt8;
+          decorativeClass: UInt8;
+          weight: UInt8;
+          aspect: UInt8;
+          contrast: UInt8;
+          serifVariant: UInt8;
+          treatment: UInt8;
+          lining: UInt8;
+          topology: UInt8;
+          characterRange: UInt8;
+        end);
+    5: (symbol: record
+          familyKind: UInt8;
+          symbolKind: UInt8;
+          weight: UInt8;
+          spacing: UInt8;
+          aspectRatioAndContrast: UInt8;
+          aspectRatio94: UInt8;
+          aspectRatio119: UInt8;
+          aspectRatio157: UInt8;
+          aspectRatio163: UInt8;
+          aspectRatio211: UInt8;
+        end);
+  end;
+
+type
+  PBLFontFaceVirt = Pointer;
+
+type
+  BLFontFaceImpl = record
+    virt: PBLFontFaceVirt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    weight: UInt16;
+    stretch: UInt8;
+    style: UInt8;
+    faceInfo: BLFontFaceInfo;
+    uniqueId: BLUniqueId;
+    data: BLFontDataCore;
+    fullName: BLStringCore;
+    familyName: BLStringCore;
+    subfamilyName: BLStringCore;
+    postScriptName: BLStringCore;
+    designMetrics: BLFontDesignMetrics;
+    unicodeCoverage: BLFontUnicodeCoverage;
+    panose: BLFontPanose;
+  end;
+  _PBLFontFaceImpl = ^BLFontFaceImpl;
+
+type
+  BLFontFaceCore = record
+    impl: _PBLFontFaceImpl;
+  end;
+  PBLFontFaceCore = ^BLFontFaceCore;
+
+type
+  BLFontMatrix = record
+  case Integer of
+    0: (m: array [0..3] of Double);
+    1: (m00: Double;
+        m01: Double;
+        m10: Double;
+        m11: Double
+        );
+  end;
+  _PBLFontMatrix = ^BLFontMatrix;
+
+type
+  BLFontMetrics = record
+    size: Single;
+    ascent: Single;
+    vAscent: Single;
+    descent: Single;
+    vDescent: Single;
+    lineGap: Single;
+    xHeight: Single;
+    capHeight: Single;
+    xMin: Single;
+    yMin: Single;
+    xMax: Single;
+    yMax: Single;
+    underlinePosition: Single;
+    underlineThickness: Single;
+    strikethroughPosition: Single;
+    strikethroughThickness: Single;
+  end;
+  _PBLFontMetrics = ^BLFontMetrics;
+
+type
+  BLFontImpl = record
+    face: BLFontFaceCore;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    weight: UInt16;
+    stretch: UInt8;
+    style: UInt8;
+    features: BLArrayCore;
+    variations: BLArrayCore;
+    metrics: BLFontMetrics;
+    matrix: BLFontMatrix;
+  end;
+  _PBLFontImpl = ^BLFontImpl;
+
+type
+  BLFontCore = record
+    impl: _PBLFontImpl;
+  end;
+  PBLFontCore = ^BLFontCore;
+
+type
+  PBLFontManagerVirt = Pointer;
+
+type
+  BLFontManagerImpl = record
+    virt: PBLFontManagerVirt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    reserved: array [0..3] of UInt8;
+  end;
+  _PBLFontManagerImpl = ^BLFontManagerImpl;
+
+type
+  BLFontManagerCore = record
+    impl: _PBLFontManagerImpl;
+  end;
+  PBLFontManagerCore = ^BLFontManagerCore;
+
+type
+  BLFontQueryProperties = record
+    style: UInt32;
+    weight: UInt32;
+    stretch: UInt32;
+  end;
+  PBLFontQueryProperties = ^BLFontQueryProperties;
+
+type
+  BLFontTable = record
+    data: Pointer;
+    size: NativeUInt;
+  end;
+  _PBLFontTable = ^BLFontTable;
+
+type
+  BLFontVariation = record
+    tag: BLTag;
+    value: Single;
+  end;
+
+type
+  BLFormatInfo = record
+    depth: Int32;
+    flags: UInt32;
+    case Integer of
+      0: (sizes: array [0..3] of UInt8;
+          shifts: array [0..3] of UInt8);
+      1: (rSize: UInt8;
+          gSize: UInt8;
+          bSize: UInt8;
+          aSize: UInt8;
+          rShift: UInt8;
+          gShift: UInt8;
+          bShift: UInt8;
+          aShift: UInt8);
+      2: (palette: _PBLRgba32);
+  end;
+  _PBLFormatInfo = ^BLFormatInfo;
+
+type
+  BLGlyphPlacement = record
+    placement: BLPointI;
+    advance: BLPointI;
+  end;
+  _PBLGlyphPlacement = ^BLGlyphPlacement;
+
+type
+  BLGlyphRun = record
+    glyphData: Pointer;
+    placementData: Pointer;
+    size: NativeUInt;
+    glyphSize: UInt8;
+    placementType: UInt8;
+    glyphAdvance: Int8;
+    placementAdvance: Int8;
+    flags: UInt32;
+  end;
+  _PBLGlyphRun = ^BLGlyphRun;
+
+type
+  BLGlyphInfo = record
+    cluster: UInt32;
+    reserved: array [0..1] of UInt32;
+  end;
+  _PBLGlyphInfo = ^BLGlyphInfo;
+
+type
+  BLGlyphBufferImpl = record
+    data: record
+        case Integer of
+          0: (content: PUInt32;
+              placementData: _PBLGlyphPlacement;
+              size: NativeUInt;
+              reserved: UInt32;
+              flags: UInt32);
+          1: (glyphRun: BLGlyphRun);
+        end;
+    infoData: _PBLGlyphInfo;
+  end;
+  _PBLGlyphBufferImpl = ^BLGlyphBufferImpl;
+
+type
+  BLGlyphBufferCore = record
+    impl: _PBLGlyphBufferImpl;
+  end;
+  PBLGlyphBufferCore = ^BLGlyphBufferCore;
+
+type
+  BLGlyphMappingState = record
+    glyphCount: NativeUInt;
+    undefinedFirst: NativeUInt;
+    undefinedCount: NativeUInt;
+  end;
+  _PBLGlyphMappingState = ^BLGlyphMappingState;
+
+type
+  BLGlyphOutlineSinkInfo = record
+    glyphIndex: NativeUInt;
+    contourCount: NativeUInt;
+  end;
+  _PBLGlyphOutlineSinkInfo = ^BLGlyphOutlineSinkInfo;
+
+type
+  BLGradientStop = record
+    offset: Double;
+    rgba: BLRgba64;
+  end;
+  _PBLGradientStop = ^BLGradientStop;
+
+type
+  BLLinearGradientValues = record
+    x0: Double;
+    y0: Double;
+    x1: Double;
+    y1: Double;
+  end;
+
+type
+  BLRadialGradientValues = record
+    x0: Double;
+    y0: Double;
+    x1: Double;
+    y1: Double;
+    r0: Double;
+  end;
+
+type
+  BLConicalGradientValues = record
+    x0: Double;
+    y0: Double;
+    angle: Double;
+  end;
+
+type
+  BLGradientImpl = record
+    capacity: NativeUInt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    gradientType: UInt8;
+    extendMode: UInt8;
+    matrixType: UInt8;
+    reserved: array [0..0] of UInt8;
+    stops: record
+      stops: _PBLGradientStop;
+      size: NativeUInt;
+    end;
+    matrix: BLMatrix2D;
+    case Integer of
+      0: (values: array [0..5] of Double);
+      1: (linear: BLLinearGradientValues);
+      2: (radial: BLRadialGradientValues);
+      3: (conical: BLConicalGradientValues);
+  end;
+  _PBLGradientImpl = ^BLGradientImpl;
+
+type
+  BLGradientCore = record
+    impl: _PBLGradientImpl;
+  end;
+  PBLGradientCore = ^BLGradientCore;
+
+type
+  PBLImageCodecVirt = Pointer;
+
+type
+  BLImageCodecImpl = record
+    virt: PBLImageCodecVirt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    features: UInt32;
+    name: PUTF8Char;
+    vendor: PUTF8Char;
+    mimeType: PUTF8Char;
+    extensions: PUTF8Char;
+  end;
+  _PBLImageCodecImpl = ^BLImageCodecImpl;
+
+type
+  BLImageCodecCore = record
+    impl: _PBLImageCodecImpl;
+  end;
+  PBLImageCodecCore = ^BLImageCodecCore;
+
+type
+  PBLImageDecoderVirt = Pointer;
+
+type
+  BLImageDecoderImpl = record
+    virt: PBLImageDecoderVirt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    lastResult: BLResult;
+    codec: BLImageCodecCore;
+    handle: Pointer;
+    frameIndex: UInt64;
+    bufferIndex: NativeUInt;
+  end;
+  _PBLImageDecoderImpl = ^BLImageDecoderImpl;
+
+type
+  BLImageDecoderCore = record
+    impl: _PBLImageDecoderImpl;
+  end;
+  PBLImageDecoderCore = ^BLImageDecoderCore;
+
+type
+  PBLImageEncoderVirt = Pointer;
+
+type
+  BLImageEncoderImpl = record
+    virt: PBLImageEncoderVirt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    lastResult: BLResult;
+    codec: BLImageCodecCore;
+    handle: Pointer;
+    frameIndex: UInt64;
+    bufferIndex: NativeUInt;
+  end;
+  _PBLImageEncoderImpl = ^BLImageEncoderImpl;
+
+type
+  BLImageEncoderCore = record
+    impl: _PBLImageEncoderImpl;
+  end;
+  PBLImageEncoderCore = ^BLImageEncoderCore;
+
+type
+  BLImageData = record
+    pixelData: Pointer;
+    stride: IntPtr;
+    size: BLSizeI;
+    format: UInt32;
+    flags: UInt32;
+  end;
+  _PBLImageData = ^BLImageData;
+
+type
+  BLImageInfo = record
+    size: BLSizeI;
+    density: BLSize;
+    flags: UInt32;
+    depth: UInt16;
+    planeCount: UInt16;
+    frameCount: UInt64;
+    format: array [0..15] of UTF8Char;
+    compression: array [0..15] of UTF8Char;
+  end;
+  _PBLImageInfo = ^BLImageInfo;
+
+type
+  BLImageScaleUserFunc = function(dst: PDouble; tArray: PDouble; n: NativeUInt; data: Pointer): Cardinal; cdecl;
+
+type
+  BLImageScaleOptions = record
+    userFunc: BLImageScaleUserFunc;
+    userData: Pointer;
+    radius: Double;
+    case Integer of
+      0: (data: array [0..2] of Double);
+      1: (mitchell: record
+            b: Double;
+            c: Double
+          end);
+  end;
+  _PBLImageScaleOptions = ^BLImageScaleOptions;
+
+type
+  BLPatternImpl = record
+    image: BLImageCore;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    patternType: UInt8;
+    extendMode: UInt8;
+    matrixType: UInt8;
+    reserved: array [0..0] of UInt8;
+    matrix: BLMatrix2D;
+    area: BLRectI;
+  end;
+  _PBLPatternImpl = ^BLPatternImpl;
+
+type
+  BLPatternCore = record
+    impl: _PBLPatternImpl;
+  end;
+  PBLPatternCore = ^BLPatternCore;
+
+type
+  BLPathView = record
+    commandData: PUInt8;
+    vertexData: _PBLPoint;
+    size: NativeUInt;
+  end;
+
+type
+  BLPathImpl = record
+    capacity: NativeUInt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    flags: UInt32;
+    case Integer of
+      0: (commandData: PUInt8;
+          vertexData: _PBLPoint;
+          size: NativeUInt);
+      1: (view: BLPathView);
+  end;
+  _PBLPathImpl = ^BLPathImpl;
+
+type
+  BLPathCore = record
+    impl: _PBLPathImpl;
+  end;
+  PBLPathCore = ^BLPathCore;
+
+type
+  BLPathSinkFunc = function(path: PBLPathCore; info: Pointer; closure: Pointer): Cardinal; cdecl;
+
+type
+  BLPixelConverterOptions = record
+    origin: BLPointI;
+    gap: NativeUInt;
+  end;
+  _PBLPixelConverterOptions = ^BLPixelConverterOptions;
+
+type
+  PBLPixelConverterCore = ^BLPixelConverterCore;
+
+  BLPixelConverterFunc = function(self: PBLPixelConverterCore; dstData: PUInt8; dstStride: IntPtr; srcData: PUInt8; srcStride: IntPtr; w: UInt32; h: UInt32; options: _PBLPixelConverterOptions): Cardinal; cdecl;
+
+  BLPixelConverterCore = record
+  case Integer of
+    0: (convertFunc: BLPixelConverterFunc;
+        internalFlags: UInt8);
+    1: (data: array [0..79] of UInt8);
+  end;
+
+type
+  BLRandom = record
+    data: array [0..1] of UInt64;
+  end;
+  _PBLRandom = ^BLRandom;
+
+type
+  BLRange = record
+    start: NativeUInt;
+    &end: NativeUInt;
+  end;
+  _PBLRange = ^BLRange;
+
+type
+  BLRegionView = record
+    data: _PBLBoxI;
+    size: NativeUInt;
+  end;
+
+type
+  BLRegionImpl = record
+    capacity: NativeUInt;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    reserved: array [0..3] of UInt8;
+    data: record
+      case Integer of
+        0: (data: _PBLBoxI;
+            size: NativeUInt);
+        1: (view: BLRegionView);
+      end;
+    boundingBox: BLBoxI;
+  end;
+  _PBLRegionImpl = ^BLRegionImpl;
+
+type
+  BLRegionCore = record
+    impl: _PBLRegionImpl;
+  end;
+  PBLRegionCore = ^BLRegionCore;
+
+type
+  BLRuntimeBuildInfo = record
+    version: record
+      case Integer of
+        0: (version: UInt32);
+        1: (patchVersion: UInt8;
+            minorVersion: UInt8;
+            majorVersion: UInt16);
+      end;
+    buildType: UInt32;
+    baselineCpuFeatures: UInt32;
+    supportedCpuFeatures: UInt32;
+    maxImageSize: Int32;
+    maxThreadCount: Int32;
+    reserved: array [0..1] of UInt32;
+    compilerInfo: array [0..31] of UTF8Char;
+  end;
+
+type
+  BLRuntimeSystemInfo = record
+    cpuArch: UInt32;
+    cpuFeatures: UInt32;
+    coreCount: Int32;
+    threadCount: Int32;
+    threadStackSize: Int32;
+    removed: Int32;
+    allocationGranularity: Int32;
+    reserved: array [0..4] of UInt32;
+  end;
+
+type
+  BLRuntimeResourceInfo = record
+    vmUsed: NativeInt;
+    vmReserved: NativeInt;
+    vmOverhead: NativeInt;
+    vmBlockCount: NativeInt;
+    zmUsed: NativeInt;
+    zmReserved: NativeInt;
+    zmOverhead: NativeInt;
+    zmBlockCount: NativeInt;
+    dynamicPipelineCount: NativeInt;
+    fileHandleCount: NativeInt;
+    fileMappingCount: NativeInt;
+    reserved: array [0..4] of NativeInt;
+  end;
+
+type
+  BLTextMetrics = record
+    advance: BLPoint;
+    leadingBearing: BLPoint;
+    trailingBearing: BLPoint;
+    boundingBox: BLBox;
+  end;
+  _PBLTextMetrics = ^BLTextMetrics;
+
+type
+  BLVariantImpl = record
+    f1: record
+      case Integer of
+        0: (virt: Pointer);
+        1: (unknownHeaderData: UIntPtr);
+    end;
+    refCount: NativeUInt;
+    implType: UInt8;
+    implTraits: UInt8;
+    memPoolData: UInt16;
+    reserved: array [0..3] of UInt8;
+  end;
+  _PBLVariantImpl = ^BLVariantImpl;
+
+type
+  BLVariantCore = record
+    impl: _PBLVariantImpl;
+  end;
+  PBLVariantCore = ^BLVariantCore;
+
+type
+  BLStyleCore = record
+  case Integer of
+    0: (rgba: BLRgba);
+    1: (variant: BLVariantCore);
+    2: (pattern: BLPatternCore);
+    3: (gradient: BLGradientCore);
+    4: (data: record
+          unknown: UInt64;
+          &type: UInt32;
+          tag: UInt32;
+        end);
+    5: (u64data: array [0..1] of UInt64);
+  end;
+  PBLStyleCore = ^BLStyleCore;
+
+
+function blArrayInit(self: PBLArrayCore; arrayTypeId: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInit';
+
+function blArrayDestroy(self: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayDestroy';
+
+function blArrayReset(self: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReset';
+
+function blArrayCreateFromData(self: PBLArrayCore; data: Pointer; size: NativeUInt; capacity: NativeUInt; dataAccessFlags: UInt32; destroyFunc: BLDestroyImplFunc; destroyData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayCreateFromData';
+
+function blArrayGetSize(self: PBLArrayCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayGetSize';
+
+function blArrayGetCapacity(self: PBLArrayCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayGetCapacity';
+
+function blArrayGetData(self: PBLArrayCore): Pointer; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayGetData';
+
+function blArrayClear(self: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayClear';
+
+function blArrayShrink(self: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayShrink';
+
+function blArrayReserve(self: PBLArrayCore; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReserve';
+
+function blArrayResize(self: PBLArrayCore; n: NativeUInt; fill: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayResize';
+
+function blArrayMakeMutable(self: PBLArrayCore; dataOut: PPointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayMakeMutable';
+
+function blArrayModifyOp(self: PBLArrayCore; op: UInt32; n: NativeUInt; dataOut: PPointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayModifyOp';
+
+function blArrayInsertOp(self: PBLArrayCore; index: NativeUInt; n: NativeUInt; dataOut: PPointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInsertOp';
+
+function blArrayAssignMove(self: PBLArrayCore; other: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAssignMove';
+
+function blArrayAssignWeak(self: PBLArrayCore; other: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAssignWeak';
+
+function blArrayAssignDeep(self: PBLArrayCore; other: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAssignDeep';
+
+function blArrayAssignView(self: PBLArrayCore; items: Pointer; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAssignView';
+
+function blArrayAppendU8(self: PBLArrayCore; value: UInt8): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAppendU8';
+
+function blArrayAppendU16(self: PBLArrayCore; value: UInt16): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAppendU16';
+
+function blArrayAppendU32(self: PBLArrayCore; value: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAppendU32';
+
+function blArrayAppendU64(self: PBLArrayCore; value: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAppendU64';
+
+function blArrayAppendF32(self: PBLArrayCore; value: Single): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAppendF32';
+
+function blArrayAppendF64(self: PBLArrayCore; value: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAppendF64';
+
+function blArrayAppendItem(self: PBLArrayCore; item: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAppendItem';
+
+function blArrayAppendView(self: PBLArrayCore; items: Pointer; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayAppendView';
+
+function blArrayInsertU8(self: PBLArrayCore; index: NativeUInt; value: UInt8): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInsertU8';
+
+function blArrayInsertU16(self: PBLArrayCore; index: NativeUInt; value: UInt16): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInsertU16';
+
+function blArrayInsertU32(self: PBLArrayCore; index: NativeUInt; value: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInsertU32';
+
+function blArrayInsertU64(self: PBLArrayCore; index: NativeUInt; value: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInsertU64';
+
+function blArrayInsertF32(self: PBLArrayCore; index: NativeUInt; value: Single): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInsertF32';
+
+function blArrayInsertF64(self: PBLArrayCore; index: NativeUInt; value: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInsertF64';
+
+function blArrayInsertItem(self: PBLArrayCore; index: NativeUInt; item: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInsertItem';
+
+function blArrayInsertView(self: PBLArrayCore; index: NativeUInt; items: Pointer; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayInsertView';
+
+function blArrayReplaceU8(self: PBLArrayCore; index: NativeUInt; value: UInt8): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReplaceU8';
+
+function blArrayReplaceU16(self: PBLArrayCore; index: NativeUInt; value: UInt16): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReplaceU16';
+
+function blArrayReplaceU32(self: PBLArrayCore; index: NativeUInt; value: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReplaceU32';
+
+function blArrayReplaceU64(self: PBLArrayCore; index: NativeUInt; value: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReplaceU64';
+
+function blArrayReplaceF32(self: PBLArrayCore; index: NativeUInt; value: Single): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReplaceF32';
+
+function blArrayReplaceF64(self: PBLArrayCore; index: NativeUInt; value: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReplaceF64';
+
+function blArrayReplaceItem(self: PBLArrayCore; index: NativeUInt; item: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReplaceItem';
+
+function blArrayReplaceView(self: PBLArrayCore; rStart: NativeUInt; rEnd: NativeUInt; items: Pointer; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayReplaceView';
+
+function blArrayRemoveIndex(self: PBLArrayCore; index: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayRemoveIndex';
+
+function blArrayRemoveRange(self: PBLArrayCore; rStart: NativeUInt; rEnd: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayRemoveRange';
+
+function blArrayEquals(a: PBLArrayCore; b: PBLArrayCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blArrayEquals';
+
+
+function blContextInit(self: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextInit';
+
+function blContextInitAs(self: PBLContextCore; image: PBLImageCore; options: _PBLContextCreateInfo): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextInitAs';
+
+function blContextDestroy(self: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextDestroy';
+
+function blContextReset(self: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextReset';
+
+function blContextAssignMove(self: PBLContextCore; other: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextAssignMove';
+
+function blContextAssignWeak(self: PBLContextCore; other: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextAssignWeak';
+
+function blContextGetType(self: PBLContextCore): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextGetType';
+
+function blContextGetTargetSize(self: PBLContextCore; targetSizeOut: _PBLSize): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextGetTargetSize';
+
+function blContextGetTargetImage(self: PBLContextCore): PBLImageCore; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextGetTargetImage';
+
+function blContextBegin(self: PBLContextCore; image: PBLImageCore; options: _PBLContextCreateInfo): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextBegin';
+
+function blContextEnd(self: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextEnd';
+
+function blContextFlush(self: PBLContextCore; flags: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFlush';
+
+function blContextQueryProperty(self: PBLContextCore; propertyId: UInt32; valueOut: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextQueryProperty';
+
+function blContextSave(self: PBLContextCore; cookie: _PBLContextCookie): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSave';
+
+function blContextRestore(self: PBLContextCore; cookie: _PBLContextCookie): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextRestore';
+
+function blContextGetMetaMatrix(self: PBLContextCore; m: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextGetMetaMatrix';
+
+function blContextGetUserMatrix(self: PBLContextCore; m: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextGetUserMatrix';
+
+function blContextUserToMeta(self: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextUserToMeta';
+
+function blContextMatrixOp(self: PBLContextCore; opType: UInt32; opData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextMatrixOp';
+
+function blContextSetHint(self: PBLContextCore; hintType: UInt32; value: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetHint';
+
+function blContextSetHints(self: PBLContextCore; hints: _PBLContextHints): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetHints';
+
+function blContextSetFlattenMode(self: PBLContextCore; mode: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetFlattenMode';
+
+function blContextSetFlattenTolerance(self: PBLContextCore; tolerance: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetFlattenTolerance';
+
+function blContextSetApproximationOptions(self: PBLContextCore; options: _PBLApproximationOptions): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetApproximationOptions';
+
+function blContextSetCompOp(self: PBLContextCore; compOp: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetCompOp';
+
+function blContextSetGlobalAlpha(self: PBLContextCore; alpha: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetGlobalAlpha';
+
+function blContextSetFillAlpha(self: PBLContextCore; alpha: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetFillAlpha';
+
+function blContextGetFillStyle(self: PBLContextCore; styleOut: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextGetFillStyle';
+
+function blContextSetFillStyle(self: PBLContextCore; style: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetFillStyle';
+
+function blContextSetFillStyleRgba(self: PBLContextCore; rgba: _PBLRgba): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetFillStyleRgba';
+
+function blContextSetFillStyleRgba32(self: PBLContextCore; rgba32: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetFillStyleRgba32';
+
+function blContextSetFillStyleRgba64(self: PBLContextCore; rgba64: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetFillStyleRgba64';
+
+function blContextSetFillStyleObject(self: PBLContextCore; &object: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetFillStyleObject';
+
+function blContextSetFillRule(self: PBLContextCore; fillRule: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetFillRule';
+
+function blContextSetStrokeAlpha(self: PBLContextCore; alpha: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeAlpha';
+
+function blContextGetStrokeStyle(self: PBLContextCore; styleout: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextGetStrokeStyle';
+
+function blContextSetStrokeStyle(self: PBLContextCore; style: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeStyle';
+
+function blContextSetStrokeStyleRgba(self: PBLContextCore; rgba: _PBLRgba): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeStyleRgba';
+
+function blContextSetStrokeStyleRgba32(self: PBLContextCore; rgba32: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeStyleRgba32';
+
+function blContextSetStrokeStyleRgba64(self: PBLContextCore; rgba64: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeStyleRgba64';
+
+function blContextSetStrokeStyleObject(self: PBLContextCore; &object: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeStyleObject';
+
+function blContextSetStrokeWidth(self: PBLContextCore; width: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeWidth';
+
+function blContextSetStrokeMiterLimit(self: PBLContextCore; miterLimit: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeMiterLimit';
+
+function blContextSetStrokeCap(self: PBLContextCore; position: UInt32; strokeCap: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeCap';
+
+function blContextSetStrokeCaps(self: PBLContextCore; strokeCap: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeCaps';
+
+function blContextSetStrokeJoin(self: PBLContextCore; strokeJoin: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeJoin';
+
+function blContextSetStrokeDashOffset(self: PBLContextCore; dashOffset: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeDashOffset';
+
+function blContextSetStrokeDashArray(self: PBLContextCore; dashArray: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeDashArray';
+
+function blContextSetStrokeTransformOrder(self: PBLContextCore; transformOrder: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeTransformOrder';
+
+function blContextGetStrokeOptions(self: PBLContextCore; options: PBLStrokeOptionsCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextGetStrokeOptions';
+
+function blContextSetStrokeOptions(self: PBLContextCore; options: PBLStrokeOptionsCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextSetStrokeOptions';
+
+function blContextClipToRectI(self: PBLContextCore; rect: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextClipToRectI';
+
+function blContextClipToRectD(self: PBLContextCore; rect: _PBLRect): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextClipToRectD';
+
+function blContextRestoreClipping(self: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextRestoreClipping';
+
+function blContextClearAll(self: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextClearAll';
+
+function blContextClearRectI(self: PBLContextCore; rect: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextClearRectI';
+
+function blContextClearRectD(self: PBLContextCore; rect: _PBLRect): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextClearRectD';
+
+function blContextFillAll(self: PBLContextCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFillAll';
+
+function blContextFillRectI(self: PBLContextCore; rect: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFillRectI';
+
+function blContextFillRectD(self: PBLContextCore; rect: _PBLRect): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFillRectD';
+
+function blContextFillPathD(self: PBLContextCore; path: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFillPathD';
+
+function blContextFillGeometry(self: PBLContextCore; geometryType: UInt32; geometryData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFillGeometry';
+
+function blContextFillTextI(self: PBLContextCore; pt: _PBLPointI; font: PBLFontCore; text: Pointer; size: NativeUInt; encoding: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFillTextI';
+
+function blContextFillTextD(self: PBLContextCore; pt: _PBLPoint; font: PBLFontCore; text: Pointer; size: NativeUInt; encoding: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFillTextD';
+
+function blContextFillGlyphRunI(self: PBLContextCore; pt: _PBLPointI; font: PBLFontCore; glyphRun: _PBLGlyphRun): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFillGlyphRunI';
+
+function blContextFillGlyphRunD(self: PBLContextCore; pt: _PBLPoint; font: PBLFontCore; glyphRun: _PBLGlyphRun): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextFillGlyphRunD';
+
+function blContextStrokeRectI(self: PBLContextCore; rect: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextStrokeRectI';
+
+function blContextStrokeRectD(self: PBLContextCore; rect: _PBLRect): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextStrokeRectD';
+
+function blContextStrokePathD(self: PBLContextCore; path: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextStrokePathD';
+
+function blContextStrokeGeometry(self: PBLContextCore; geometryType: UInt32; geometryData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextStrokeGeometry';
+
+function blContextStrokeTextI(self: PBLContextCore; pt: _PBLPointI; font: PBLFontCore; text: Pointer; size: NativeUInt; encoding: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextStrokeTextI';
+
+function blContextStrokeTextD(self: PBLContextCore; pt: _PBLPoint; font: PBLFontCore; text: Pointer; size: NativeUInt; encoding: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextStrokeTextD';
+
+function blContextStrokeGlyphRunI(self: PBLContextCore; pt: _PBLPointI; font: PBLFontCore; glyphRun: _PBLGlyphRun): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextStrokeGlyphRunI';
+
+function blContextStrokeGlyphRunD(self: PBLContextCore; pt: _PBLPoint; font: PBLFontCore; glyphRun: _PBLGlyphRun): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextStrokeGlyphRunD';
+
+function blContextBlitImageI(self: PBLContextCore; pt: _PBLPointI; img: PBLImageCore; imgArea: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextBlitImageI';
+
+function blContextBlitImageD(self: PBLContextCore; pt: _PBLPoint; img: PBLImageCore; imgArea: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextBlitImageD';
+
+function blContextBlitScaledImageI(self: PBLContextCore; rect: _PBLRectI; img: PBLImageCore; imgArea: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextBlitScaledImageI';
+
+function blContextBlitScaledImageD(self: PBLContextCore; rect: _PBLRect; img: PBLImageCore; imgArea: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blContextBlitScaledImageD';
+
+
+function blFileInit(self: PBLFileCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileInit';
+
+function blFileReset(self: PBLFileCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileReset';
+
+function blFileOpen(self: PBLFileCore; fileName: PUTF8Char; openFlags: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileOpen';
+
+function blFileClose(self: PBLFileCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileClose';
+
+function blFileSeek(self: PBLFileCore; offset: Int64; seekType: UInt32; positionOut: PInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileSeek';
+
+function blFileRead(self: PBLFileCore; buffer: Pointer; n: NativeUInt; bytesReadOut: PNativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileRead';
+
+function blFileWrite(self: PBLFileCore; buffer: Pointer; n: NativeUInt; bytesWrittenOut: PNativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileWrite';
+
+function blFileTruncate(self: PBLFileCore; maxSize: Int64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileTruncate';
+
+function blFileGetSize(self: PBLFileCore; fileSizeOut: PUInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileGetSize';
+
+
+function blFileSystemReadFile(fileName: PUTF8Char; dst: PBLArrayCore; maxSize: NativeUInt; readFlags: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileSystemReadFile';
+
+function blFileSystemWriteFile(fileName: PUTF8Char; data: Pointer; size: NativeUInt; bytesWrittenOut: PNativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFileSystemWriteFile';
+
+
+function blFontInit(self: PBLFontCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontInit';
+
+function blFontDestroy(self: PBLFontCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDestroy';
+
+function blFontReset(self: PBLFontCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontReset';
+
+function blFontAssignMove(self: PBLFontCore; other: PBLFontCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontAssignMove';
+
+function blFontAssignWeak(self: PBLFontCore; other: PBLFontCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontAssignWeak';
+
+function blFontEquals(a: PBLFontCore; b: PBLFontCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontEquals';
+
+function blFontCreateFromFace(self: PBLFontCore; face: PBLFontFaceCore; size: Single): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontCreateFromFace';
+
+function blFontShape(self: PBLFontCore; gb: PBLGlyphBufferCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontShape';
+
+function blFontMapTextToGlyphs(self: PBLFontCore; gb: PBLGlyphBufferCore; stateOut: _PBLGlyphMappingState): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontMapTextToGlyphs';
+
+function blFontPositionGlyphs(self: PBLFontCore; gb: PBLGlyphBufferCore; positioningFlags: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontPositionGlyphs';
+
+function blFontApplyKerning(self: PBLFontCore; gb: PBLGlyphBufferCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontApplyKerning';
+
+function blFontApplyGSub(self: PBLFontCore; gb: PBLGlyphBufferCore; index: NativeUInt; lookups: BLBitWord): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontApplyGSub';
+
+function blFontApplyGPos(self: PBLFontCore; gb: PBLGlyphBufferCore; index: NativeUInt; lookups: BLBitWord): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontApplyGPos';
+
+function blFontGetMatrix(self: PBLFontCore; &out: _PBLFontMatrix): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontGetMatrix';
+
+function blFontGetMetrics(self: PBLFontCore; &out: _PBLFontMetrics): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontGetMetrics';
+
+function blFontGetDesignMetrics(self: PBLFontCore; &out: _PBLFontDesignMetrics): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontGetDesignMetrics';
+
+function blFontGetTextMetrics(self: PBLFontCore; gb: PBLGlyphBufferCore; &out: _PBLTextMetrics): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontGetTextMetrics';
+
+function blFontGetGlyphBounds(self: PBLFontCore; glyphData: PUInt32; glyphAdvance: IntPtr; &out: _PBLBoxI; count: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontGetGlyphBounds';
+
+function blFontGetGlyphAdvances(self: PBLFontCore; glyphData: PUInt32; glyphAdvance: IntPtr; &out: _PBLGlyphPlacement; count: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontGetGlyphAdvances';
+
+function blFontGetGlyphOutlines(self: PBLFontCore; glyphId: UInt32; userMatrix: _PBLMatrix2D; &out: PBLPathCore; sink: BLPathSinkFunc; closure: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontGetGlyphOutlines';
+
+function blFontGetGlyphRunOutlines(self: PBLFontCore; glyphRun: _PBLGlyphRun; userMatrix: _PBLMatrix2D; &out: PBLPathCore; sink: BLPathSinkFunc; closure: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontGetGlyphRunOutlines';
+
+
+function blFontDataInit(self: PBLFontDataCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataInit';
+
+function blFontDataDestroy(self: PBLFontDataCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataDestroy';
+
+function blFontDataReset(self: PBLFontDataCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataReset';
+
+function blFontDataAssignMove(self: PBLFontDataCore; other: PBLFontDataCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataAssignMove';
+
+function blFontDataAssignWeak(self: PBLFontDataCore; other: PBLFontDataCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataAssignWeak';
+
+function blFontDataCreateFromFile(self: PBLFontDataCore; fileName: PUTF8Char; readFlags: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataCreateFromFile';
+
+function blFontDataCreateFromDataArray(self: PBLFontDataCore; dataArray: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataCreateFromDataArray';
+
+function blFontDataCreateFromData(self: PBLFontDataCore; data: Pointer; dataSize: NativeUInt; destroyFunc: BLDestroyImplFunc; destroyData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataCreateFromData';
+
+function blFontDataEquals(a: PBLFontDataCore; b: PBLFontDataCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataEquals';
+
+function blFontDataListTags(self: PBLFontDataCore; faceIndex: UInt32; dst: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataListTags';
+
+function blFontDataQueryTables(self: PBLFontDataCore; faceIndex: UInt32; dst: _PBLFontTable; tags: _PBLTag; count: NativeUInt): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontDataQueryTables';
+
+
+function blFontFaceInit(self: PBLFontFaceCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceInit';
+
+function blFontFaceDestroy(self: PBLFontFaceCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceDestroy';
+
+function blFontFaceReset(self: PBLFontFaceCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceReset';
+
+function blFontFaceAssignMove(self: PBLFontFaceCore; other: PBLFontFaceCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceAssignMove';
+
+function blFontFaceAssignWeak(self: PBLFontFaceCore; other: PBLFontFaceCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceAssignWeak';
+
+function blFontFaceEquals(a: PBLFontFaceCore; b: PBLFontFaceCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceEquals';
+
+function blFontFaceCreateFromFile(self: PBLFontFaceCore; fileName: PUTF8Char; readFlags: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceCreateFromFile';
+
+function blFontFaceCreateFromData(self: PBLFontFaceCore; fontData: PBLFontDataCore; faceIndex: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceCreateFromData';
+
+function blFontFaceGetFaceInfo(self: PBLFontFaceCore; &out: _PBLFontFaceInfo): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceGetFaceInfo';
+
+function blFontFaceGetDesignMetrics(self: PBLFontFaceCore; &out: _PBLFontDesignMetrics): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceGetDesignMetrics';
+
+function blFontFaceGetUnicodeCoverage(self: PBLFontFaceCore; &out: _PBLFontUnicodeCoverage): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontFaceGetUnicodeCoverage';
+
+
+function blFontManagerInit(self: PBLFontManagerCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerInit';
+
+function blFontManagerInitNew(self: PBLFontManagerCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerInitNew';
+
+function blFontManagerDestroy(self: PBLFontManagerCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerDestroy';
+
+function blFontManagerReset(self: PBLFontManagerCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerReset';
+
+function blFontManagerAssignMove(self: PBLFontManagerCore; other: PBLFontManagerCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerAssignMove';
+
+function blFontManagerAssignWeak(self: PBLFontManagerCore; other: PBLFontManagerCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerAssignWeak';
+
+function blFontManagerCreate(self: PBLFontManagerCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerCreate';
+
+function blFontManagerGetFaceCount(const self: PBLFontManagerCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerGetFaceCount';
+
+function blFontManagerGetFamilyCount(const self: PBLFontManagerCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerGetFamilyCount';
+
+function blFontManagerHasFace(const self: PBLFontManagerCore; const face: PBLFontFaceCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerHasFace';
+
+function blFontManagerAddFace(self: PBLFontManagerCore; const face: PBLFontFaceCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerAddFace';
+
+function blFontManagerQueryFace(const self: PBLFontManagerCore; const name: MarshaledAString; nameSize: NativeUInt; const properties: PBLFontQueryProperties; _out: PBLFontFaceCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerQueryFace';
+
+function blFontManagerQueryFacesByFamilyName(const self: PBLFontManagerCore; const name: MarshaledAString; nameSize: NativeUInt; _out: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerQueryFacesByFamilyName';
+
+function blFontManagerEquals(a: PBLFontManagerCore; b: PBLFontManagerCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blFontManagerEquals';
+
+
+function blFormatInfoQuery(self: _PBLFormatInfo; format: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFormatInfoQuery';
+
+function blFormatInfoSanitize(self: _PBLFormatInfo): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blFormatInfoSanitize';
+
+
+function blGlyphBufferInit(self: PBLGlyphBufferCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferInit';
+
+function blGlyphBufferInitMove(self: PBLGlyphBufferCore; other: PBLGlyphBufferCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferInitMove';
+
+function blGlyphBufferDestroy(self: PBLGlyphBufferCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferDestroy';
+
+function blGlyphBufferReset(self: PBLGlyphBufferCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferReset';
+
+function blGlyphBufferClear(self: PBLGlyphBufferCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferClear';
+
+function blGlyphBufferGetSize(self: PBLGlyphBufferCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferGetSize';
+
+function blGlyphBufferGetFlags(self: PBLGlyphBufferCore): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferGetFlags';
+
+function blGlyphBufferGetGlyphRun(self: PBLGlyphBufferCore): _PBLGlyphRun; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferGetGlyphRun';
+
+function blGlyphBufferGetContent(self: PBLGlyphBufferCore): PUInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferGetContent';
+
+function blGlyphBufferGetInfoData(self: PBLGlyphBufferCore): _PBLGlyphInfo; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferGetInfoData';
+
+function blGlyphBufferGetPlacementData(self: PBLGlyphBufferCore): _PBLGlyphPlacement; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferGetPlacementData';
+
+function blGlyphBufferSetText(self: PBLGlyphBufferCore; textData: Pointer; size: NativeUInt; encoding: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferSetText';
+
+function blGlyphBufferSetGlyphs(self: PBLGlyphBufferCore; glyphData: PUInt32; size: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferSetGlyphs';
+
+function blGlyphBufferSetGlyphsFromStruct(self: PBLGlyphBufferCore; glyphData: Pointer; size: NativeUInt; glyphIdSize: NativeUInt; glyphIdAdvance: IntPtr): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGlyphBufferSetGlyphsFromStruct';
+
+
+function blGradientInit(self: PBLGradientCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientInit';
+
+function blGradientInitAs(self: PBLGradientCore; &type: UInt32; values: Pointer; extendMode: UInt32; stops: _PBLGradientStop; n: NativeUInt; m: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientInitAs';
+
+function blGradientDestroy(self: PBLGradientCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientDestroy';
+
+function blGradientReset(self: PBLGradientCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientReset';
+
+function blGradientAssignMove(self: PBLGradientCore; other: PBLGradientCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientAssignMove';
+
+function blGradientAssignWeak(self: PBLGradientCore; other: PBLGradientCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientAssignWeak';
+
+function blGradientCreate(self: PBLGradientCore; &type: UInt32; values: Pointer; extendMode: UInt32; stops: _PBLGradientStop; n: NativeUInt; m: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientCreate';
+
+function blGradientShrink(self: PBLGradientCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientShrink';
+
+function blGradientReserve(self: PBLGradientCore; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientReserve';
+
+function blGradientGetType(self: PBLGradientCore): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientGetType';
+
+function blGradientSetType(self: PBLGradientCore; &type: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientSetType';
+
+function blGradientGetValue(self: PBLGradientCore; index: NativeUInt): Double; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientGetValue';
+
+function blGradientSetValue(self: PBLGradientCore; index: NativeUInt; value: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientSetValue';
+
+function blGradientSetValues(self: PBLGradientCore; index: NativeUInt; values: PDouble; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientSetValues';
+
+function blGradientGetExtendMode(self: PBLGradientCore): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientGetExtendMode';
+
+function blGradientSetExtendMode(self: PBLGradientCore; extendMode: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientSetExtendMode';
+
+function blGradientGetSize(self: PBLGradientCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientGetSize';
+
+function blGradientGetCapacity(self: PBLGradientCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientGetCapacity';
+
+function blGradientGetStops(self: PBLGradientCore): _PBLGradientStop; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientGetStops';
+
+function blGradientResetStops(self: PBLGradientCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientResetStops';
+
+function blGradientAssignStops(self: PBLGradientCore; stops: _PBLGradientStop; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientAssignStops';
+
+function blGradientAddStopRgba32(self: PBLGradientCore; offset: Double; argb32: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientAddStopRgba32';
+
+function blGradientAddStopRgba64(self: PBLGradientCore; offset: Double; argb64: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientAddStopRgba64';
+
+function blGradientRemoveStop(self: PBLGradientCore; index: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientRemoveStop';
+
+function blGradientRemoveStopByOffset(self: PBLGradientCore; offset: Double; all: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientRemoveStopByOffset';
+
+function blGradientRemoveStops(self: PBLGradientCore; rStart: NativeUInt; rEnd: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientRemoveStops';
+
+function blGradientRemoveStopsFromTo(self: PBLGradientCore; offsetMin: Double; offsetMax: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientRemoveStopsFromTo';
+
+function blGradientReplaceStopRgba32(self: PBLGradientCore; index: NativeUInt; offset: Double; rgba32: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientReplaceStopRgba32';
+
+function blGradientReplaceStopRgba64(self: PBLGradientCore; index: NativeUInt; offset: Double; rgba64: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientReplaceStopRgba64';
+
+function blGradientIndexOfStop(self: PBLGradientCore; offset: Double): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientIndexOfStop';
+
+function blGradientApplyMatrixOp(self: PBLGradientCore; opType: UInt32; opData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientApplyMatrixOp';
+
+function blGradientEquals(a: PBLGradientCore; b: PBLGradientCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blGradientEquals';
+
+
+function blImageInit(self: PBLImageCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageInit';
+
+function blImageInitAs(self: PBLImageCore; w: Integer; h: Integer; format: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageInitAs';
+
+function blImageInitAsFromData(self: PBLImageCore; w: Integer; h: Integer; format: UInt32; pixelData: Pointer; stride: IntPtr; destroyFunc: BLDestroyImplFunc; destroyData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageInitAsFromData';
+
+function blImageDestroy(self: PBLImageCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageDestroy';
+
+function blImageReset(self: PBLImageCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageReset';
+
+function blImageAssignMove(self: PBLImageCore; other: PBLImageCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageAssignMove';
+
+function blImageAssignWeak(self: PBLImageCore; other: PBLImageCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageAssignWeak';
+
+function blImageAssignDeep(self: PBLImageCore; other: PBLImageCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageAssignDeep';
+
+function blImageCreate(self: PBLImageCore; w: Integer; h: Integer; format: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCreate';
+
+function blImageCreateFromData(self: PBLImageCore; w: Integer; h: Integer; format: UInt32; pixelData: Pointer; stride: IntPtr; destroyFunc: BLDestroyImplFunc; destroyData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCreateFromData';
+
+function blImageGetData(self: PBLImageCore; dataOut: _PBLImageData): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageGetData';
+
+function blImageMakeMutable(self: PBLImageCore; dataOut: _PBLImageData): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageMakeMutable';
+
+function blImageConvert(self: PBLImageCore; format: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageConvert';
+
+function blImageEquals(a: PBLImageCore; b: PBLImageCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageEquals';
+
+function blImageScale(dst: PBLImageCore; src: PBLImageCore; size: _PBLSizeI; filter: UInt32; options: _PBLImageScaleOptions): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageScale';
+
+function blImageReadFromFile(self: PBLImageCore; fileName: PUTF8Char; codecs: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageReadFromFile';
+
+function blImageReadFromData(self: PBLImageCore; data: Pointer; size: NativeUInt; codecs: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageReadFromData';
+
+function blImageWriteToFile(self: PBLImageCore; fileName: PUTF8Char; codec: PBLImageCodecCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageWriteToFile';
+
+function blImageWriteToData(self: PBLImageCore; dst: PBLArrayCore; codec: PBLImageCodecCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageWriteToData';
+
+
+function blImageCodecInit(self: PBLImageCodecCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecInit';
+
+function blImageCodecDestroy(self: PBLImageCodecCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecDestroy';
+
+function blImageCodecReset(self: PBLImageCodecCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecReset';
+
+function blImageCodecAssignWeak(self: PBLImageCodecCore; other: PBLImageCodecCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecAssignWeak';
+
+function blImageCodecFindByName(self: PBLImageCodecCore; name: PUTF8Char; size: NativeUInt; codecs: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecFindByName';
+
+function blImageCodecFindByExtension(self: PBLImageCodecCore; name: PUTF8Char; size: NativeUInt; codecs: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecFindByExtension';
+
+function blImageCodecFindByData(self: PBLImageCodecCore; data: Pointer; size: NativeUInt; codecs: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecFindByData';
+
+function blImageCodecInspectData(self: PBLImageCodecCore; data: Pointer; size: NativeUInt): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecInspectData';
+
+function blImageCodecCreateDecoder(self: PBLImageCodecCore; dst: PBLImageDecoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecCreateDecoder';
+
+function blImageCodecCreateEncoder(self: PBLImageCodecCore; dst: PBLImageEncoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecCreateEncoder';
+
+function blImageCodecArrayInitBuiltInCodecs(self: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecArrayInitBuiltInCodecs';
+
+function blImageCodecArrayAssignBuiltInCodecs(self: PBLArrayCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecArrayAssignBuiltInCodecs';
+
+function blImageCodecAddToBuiltIn(codec: PBLImageCodecCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecAddToBuiltIn';
+
+function blImageCodecRemoveFromBuiltIn(codec: PBLImageCodecCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageCodecRemoveFromBuiltIn';
+
+
+function blImageDecoderInit(self: PBLImageDecoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageDecoderInit';
+
+function blImageDecoderDestroy(self: PBLImageDecoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageDecoderDestroy';
+
+function blImageDecoderReset(self: PBLImageDecoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageDecoderReset';
+
+function blImageDecoderAssignMove(self: PBLImageDecoderCore; other: PBLImageDecoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageDecoderAssignMove';
+
+function blImageDecoderAssignWeak(self: PBLImageDecoderCore; other: PBLImageDecoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageDecoderAssignWeak';
+
+function blImageDecoderRestart(self: PBLImageDecoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageDecoderRestart';
+
+function blImageDecoderReadInfo(self: PBLImageDecoderCore; infoOut: _PBLImageInfo; data: PUInt8; size: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageDecoderReadInfo';
+
+function blImageDecoderReadFrame(self: PBLImageDecoderCore; imageOut: PBLImageCore; data: PUInt8; size: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageDecoderReadFrame';
+
+
+function blImageEncoderInit(self: PBLImageEncoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageEncoderInit';
+
+function blImageEncoderDestroy(self: PBLImageEncoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageEncoderDestroy';
+
+function blImageEncoderReset(self: PBLImageEncoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageEncoderReset';
+
+function blImageEncoderAssignMove(self: PBLImageEncoderCore; other: PBLImageEncoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageEncoderAssignMove';
+
+function blImageEncoderAssignWeak(self: PBLImageEncoderCore; other: PBLImageEncoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageEncoderAssignWeak';
+
+function blImageEncoderRestart(self: PBLImageEncoderCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageEncoderRestart';
+
+function blImageEncoderWriteFrame(self: PBLImageEncoderCore; dst: PBLArrayCore; image: PBLImageCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blImageEncoderWriteFrame';
+
+
+function blMatrix2DSetIdentity(self: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blMatrix2DSetIdentity';
+
+function blMatrix2DSetTranslation(self: _PBLMatrix2D; x: Double; y: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blMatrix2DSetTranslation';
+
+function blMatrix2DSetScaling(self: _PBLMatrix2D; x: Double; y: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blMatrix2DSetScaling';
+
+function blMatrix2DSetSkewing(self: _PBLMatrix2D; x: Double; y: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blMatrix2DSetSkewing';
+
+function blMatrix2DSetRotation(self: _PBLMatrix2D; angle: Double; cx: Double; cy: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blMatrix2DSetRotation';
+
+function blMatrix2DApplyOp(self: _PBLMatrix2D; opType: UInt32; opData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blMatrix2DApplyOp';
+
+function blMatrix2DInvert(dst: _PBLMatrix2D; src: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blMatrix2DInvert';
+
+function blMatrix2DGetType(self: _PBLMatrix2D): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blMatrix2DGetType';
+
+function blMatrix2DMapPointDArray(self: _PBLMatrix2D; dst: _PBLPoint; src: _PBLPoint; count: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blMatrix2DMapPointDArray';
+
+
+function blPathInit(self: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathInit';
+
+function blPathDestroy(self: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathDestroy';
+
+function blPathReset(self: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathReset';
+
+function blPathGetSize(self: PBLPathCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetSize';
+
+function blPathGetCapacity(self: PBLPathCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetCapacity';
+
+function blPathGetCommandData(self: PBLPathCore): PUInt8; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetCommandData';
+
+function blPathGetVertexData(self: PBLPathCore): _PBLPoint; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetVertexData';
+
+function blPathClear(self: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathClear';
+
+function blPathShrink(self: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathShrink';
+
+function blPathReserve(self: PBLPathCore; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathReserve';
+
+function blPathModifyOp(self: PBLPathCore; op: UInt32; n: NativeUInt; cmdDataOut: PPUInt8; out vtxDataOut: _PBLPoint): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathModifyOp';
+
+function blPathAssignMove(self: PBLPathCore; other: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAssignMove';
+
+function blPathAssignWeak(self: PBLPathCore; other: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAssignWeak';
+
+function blPathAssignDeep(self: PBLPathCore; other: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAssignDeep';
+
+function blPathSetVertexAt(self: PBLPathCore; index: NativeUInt; cmd: UInt32; x: Double; y: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathSetVertexAt';
+
+function blPathMoveTo(self: PBLPathCore; x0: Double; y0: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathMoveTo';
+
+function blPathLineTo(self: PBLPathCore; x1: Double; y1: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathLineTo';
+
+function blPathPolyTo(self: PBLPathCore; poly: _PBLPoint; count: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathPolyTo';
+
+function blPathQuadTo(self: PBLPathCore; x1: Double; y1: Double; x2: Double; y2: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathQuadTo';
+
+function blPathCubicTo(self: PBLPathCore; x1: Double; y1: Double; x2: Double; y2: Double; x3: Double; y3: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathCubicTo';
+
+function blPathSmoothQuadTo(self: PBLPathCore; x2: Double; y2: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathSmoothQuadTo';
+
+function blPathSmoothCubicTo(self: PBLPathCore; x2: Double; y2: Double; x3: Double; y3: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathSmoothCubicTo';
+
+function blPathArcTo(self: PBLPathCore; x: Double; y: Double; rx: Double; ry: Double; start: Double; sweep: Double; forceMoveTo: Boolean): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathArcTo';
+
+function blPathArcQuadrantTo(self: PBLPathCore; x1: Double; y1: Double; x2: Double; y2: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathArcQuadrantTo';
+
+function blPathEllipticArcTo(self: PBLPathCore; rx: Double; ry: Double; xAxisRotation: Double; largeArcFlag: Boolean; sweepFlag: Boolean; x1: Double; y1: Double): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathEllipticArcTo';
+
+function blPathClose(self: PBLPathCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathClose';
+
+function blPathAddGeometry(self: PBLPathCore; geometryType: UInt32; geometryData: Pointer; m: _PBLMatrix2D; dir: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddGeometry';
+
+function blPathAddBoxI(self: PBLPathCore; box: _PBLBoxI; dir: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddBoxI';
+
+function blPathAddBoxD(self: PBLPathCore; box: _PBLBox; dir: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddBoxD';
+
+function blPathAddRectI(self: PBLPathCore; rect: _PBLRectI; dir: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddRectI';
+
+function blPathAddRectD(self: PBLPathCore; rect: _PBLRect; dir: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddRectD';
+
+function blPathAddPath(self: PBLPathCore; other: PBLPathCore; range: _PBLRange): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddPath';
+
+function blPathAddTranslatedPath(self: PBLPathCore; other: PBLPathCore; range: _PBLRange; p: _PBLPoint): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddTranslatedPath';
+
+function blPathAddTransformedPath(self: PBLPathCore; other: PBLPathCore; range: _PBLRange; m: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddTransformedPath';
+
+function blPathAddReversedPath(self: PBLPathCore; other: PBLPathCore; range: _PBLRange; reverseMode: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddReversedPath';
+
+function blPathAddStrokedPath(self: PBLPathCore; other: PBLPathCore; range: _PBLRange; options: PBLStrokeOptionsCore; approx: _PBLApproximationOptions): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathAddStrokedPath';
+
+function blPathRemoveRange(self: PBLPathCore; range: _PBLRange): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathRemoveRange';
+
+function blPathTranslate(self: PBLPathCore; range: _PBLRange; p: _PBLPoint): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathTranslate';
+
+function blPathTransform(self: PBLPathCore; range: _PBLRange; m: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathTransform';
+
+function blPathFitTo(self: PBLPathCore; range: _PBLRange; rect: _PBLRect; fitFlags: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathFitTo';
+
+function blPathEquals(a: PBLPathCore; b: PBLPathCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathEquals';
+
+function blPathGetInfoFlags(self: PBLPathCore; flagsOut: PUInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetInfoFlags';
+
+function blPathGetControlBox(self: PBLPathCore; boxOut: _PBLBox): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetControlBox';
+
+function blPathGetBoundingBox(self: PBLPathCore; boxOut: _PBLBox): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetBoundingBox';
+
+function blPathGetFigureRange(self: PBLPathCore; index: NativeUInt; rangeOut: _PBLRange): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetFigureRange';
+
+function blPathGetLastVertex(self: PBLPathCore; vtxOut: _PBLPoint): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetLastVertex';
+
+function blPathGetClosestVertex(self: PBLPathCore; p: _PBLPoint; maxDistance: Double; indexOut: PNativeUInt; distanceOut: PDouble): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathGetClosestVertex';
+
+function blPathHitTest(self: PBLPathCore; p: _PBLPoint; fillRule: UInt32): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blPathHitTest';
+
+
+function blPatternInit(self: PBLPatternCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternInit';
+
+function blPatternInitAs(self: PBLPatternCore; image: PBLImageCore; area: _PBLRectI; extendMode: UInt32; m: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternInitAs';
+
+function blPatternDestroy(self: PBLPatternCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternDestroy';
+
+function blPatternReset(self: PBLPatternCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternReset';
+
+function blPatternAssignMove(self: PBLPatternCore; other: PBLPatternCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternAssignMove';
+
+function blPatternAssignWeak(self: PBLPatternCore; other: PBLPatternCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternAssignWeak';
+
+function blPatternAssignDeep(self: PBLPatternCore; other: PBLPatternCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternAssignDeep';
+
+function blPatternCreate(self: PBLPatternCore; image: PBLImageCore; area: _PBLRectI; extendMode: UInt32; m: _PBLMatrix2D): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternCreate';
+
+function blPatternSetImage(self: PBLPatternCore; image: PBLImageCore; area: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternSetImage';
+
+function blPatternSetArea(self: PBLPatternCore; area: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternSetArea';
+
+function blPatternSetExtendMode(self: PBLPatternCore; extendMode: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternSetExtendMode';
+
+function blPatternApplyMatrixOp(self: PBLPatternCore; opType: UInt32; opData: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternApplyMatrixOp';
+
+function blPatternEquals(a: PBLPatternCore; b: PBLPatternCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blPatternEquals';
+
+
+function blPixelConverterInit(self: PBLPixelConverterCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPixelConverterInit';
+
+function blPixelConverterInitWeak(self: PBLPixelConverterCore; other: PBLPixelConverterCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPixelConverterInitWeak';
+
+function blPixelConverterDestroy(self: PBLPixelConverterCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPixelConverterDestroy';
+
+function blPixelConverterReset(self: PBLPixelConverterCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPixelConverterReset';
+
+function blPixelConverterAssign(self: PBLPixelConverterCore; other: PBLPixelConverterCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPixelConverterAssign';
+
+function blPixelConverterCreate(self: PBLPixelConverterCore; dstInfo: _PBLFormatInfo; srcInfo: _PBLFormatInfo; createFlags: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPixelConverterCreate';
+
+function blPixelConverterConvert(self: PBLPixelConverterCore; dstData: Pointer; dstStride: IntPtr; srcData: Pointer; srcStride: IntPtr; w: UInt32; h: UInt32; options: _PBLPixelConverterOptions): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blPixelConverterConvert';
+
+
+function blRandomReset(self: _PBLRandom; seed: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRandomReset';
+
+function blRandomNextUInt32(self: _PBLRandom): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blRandomNextUInt32';
+
+function blRandomNextUInt64(self: _PBLRandom): UInt64; cdecl;
+  external LIB_BLEND2D name _PU + 'blRandomNextUInt64';
+
+function blRandomNextDouble(self: _PBLRandom): Double; cdecl;
+  external LIB_BLEND2D name _PU + 'blRandomNextDouble';
+
+
+function blRegionInit(self: PBLRegionCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionInit';
+
+function blRegionDestroy(self: PBLRegionCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionDestroy';
+
+function blRegionReset(self: PBLRegionCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionReset';
+
+function blRegionGetSize(self: PBLRegionCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionGetSize';
+
+function blRegionGetCapacity(self: PBLRegionCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionGetCapacity';
+
+function blRegionGetData(self: PBLRegionCore): _PBLBoxI; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionGetData';
+
+function blRegionClear(self: PBLRegionCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionClear';
+
+function blRegionShrink(self: PBLRegionCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionShrink';
+
+function blRegionReserve(self: PBLRegionCore; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionReserve';
+
+function blRegionAssignMove(self: PBLRegionCore; other: PBLRegionCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionAssignMove';
+
+function blRegionAssignWeak(self: PBLRegionCore; other: PBLRegionCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionAssignWeak';
+
+function blRegionAssignDeep(self: PBLRegionCore; other: PBLRegionCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionAssignDeep';
+
+function blRegionAssignBoxI(self: PBLRegionCore; src: _PBLBoxI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionAssignBoxI';
+
+function blRegionAssignBoxIArray(self: PBLRegionCore; data: _PBLBoxI; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionAssignBoxIArray';
+
+function blRegionAssignRectI(self: PBLRegionCore; rect: _PBLRectI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionAssignRectI';
+
+function blRegionAssignRectIArray(self: PBLRegionCore; data: _PBLRectI; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionAssignRectIArray';
+
+function blRegionCombine(self: PBLRegionCore; a: PBLRegionCore; b: PBLRegionCore; booleanOp: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionCombine';
+
+function blRegionCombineRB(self: PBLRegionCore; a: PBLRegionCore; b: _PBLBoxI; booleanOp: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionCombineRB';
+
+function blRegionCombineBR(self: PBLRegionCore; a: _PBLBoxI; b: PBLRegionCore; booleanOp: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionCombineBR';
+
+function blRegionCombineBB(self: PBLRegionCore; a: _PBLBoxI; b: _PBLBoxI; booleanOp: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionCombineBB';
+
+function blRegionTranslate(self: PBLRegionCore; r: PBLRegionCore; pt: _PBLPointI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionTranslate';
+
+function blRegionTranslateAndClip(self: PBLRegionCore; r: PBLRegionCore; pt: _PBLPointI; clipBox: _PBLBoxI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionTranslateAndClip';
+
+function blRegionIntersectAndClip(self: PBLRegionCore; a: PBLRegionCore; b: PBLRegionCore; clipBox: _PBLBoxI): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionIntersectAndClip';
+
+function blRegionEquals(a: PBLRegionCore; b: PBLRegionCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionEquals';
+
+function blRegionGetType(self: PBLRegionCore): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionGetType';
+
+function blRegionHitTest(self: PBLRegionCore; pt: _PBLPointI): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionHitTest';
+
+function blRegionHitTestBoxI(self: PBLRegionCore; box: _PBLBoxI): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blRegionHitTestBoxI';
+
+
+function blRuntimeInit(): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRuntimeInit';
+
+function blRuntimeShutdown(): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRuntimeShutdown';
+
+function blRuntimeCleanup(cleanupFlags: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRuntimeCleanup';
+
+function blRuntimeQueryInfo(infoType: UInt32; infoOut: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRuntimeQueryInfo';
+
+function blRuntimeMessageOut(msg: PUTF8Char): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRuntimeMessageOut';
+
+function blRuntimeMessageFmt(fmt: PUTF8Char): BLResult varargs; cdecl;
+  external LIB_BLEND2D name _PU + 'blRuntimeMessageFmt';
+
+function blRuntimeMessageVFmt(fmt: PUTF8Char; ap: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blRuntimeMessageVFmt';
+
+procedure blRuntimeAssertionFailure(&file: PUTF8Char; line: Integer; msg: PUTF8Char); cdecl;
+  external LIB_BLEND2D name _PU + 'blRuntimeAssertionFailure';
+
+{$IFDEF MSWINDOWS}
+function blResultFromWinError(e: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blResultFromWinError';
+{$ELSE}
+function blResultFromPosixError(e: Integer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blResultFromPosixError';
+{$ENDIF}
+
+
+function blStringInit(self: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringInit';
+
+function blStringInitWithData(self: PBLStringCore; const str: MarshaledAString; size: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringInitWithData';
+
+function blStringDestroy(self: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringDestroy';
+
+function blStringReset(self: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringReset';
+
+function blStringGetSize(self: PBLStringCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringGetSize';
+
+function blStringGetCapacity(self: PBLStringCore): NativeUInt; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringGetCapacity';
+
+function blStringGetData(self: PBLStringCore): PUTF8Char; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringGetData';
+
+function blStringClear(self: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringClear';
+
+function blStringShrink(self: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringShrink';
+
+function blStringReserve(self: PBLStringCore; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringReserve';
+
+function blStringResize(self: PBLStringCore; n: NativeUInt; fill: UTF8Char): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringResize';
+
+function blStringMakeMutable(self: PBLStringCore; dataOut: PPUTF8Char): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringMakeMutable';
+
+function blStringModifyOp(self: PBLStringCore; op: UInt32; n: NativeUInt; dataOut: PPUTF8Char): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringModifyOp';
+
+function blStringInsertOp(self: PBLStringCore; index: NativeUInt; n: NativeUInt; dataOut: PPUTF8Char): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringInsertOp';
+
+function blStringAssignMove(self: PBLStringCore; other: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringAssignMove';
+
+function blStringAssignWeak(self: PBLStringCore; other: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringAssignWeak';
+
+function blStringAssignDeep(self: PBLStringCore; other: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringAssignDeep';
+
+function blStringAssignData(self: PBLStringCore; str: PUTF8Char; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringAssignData';
+
+function blStringApplyOpChar(self: PBLStringCore; op: UInt32; c: UTF8Char; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringApplyOpChar';
+
+function blStringApplyOpData(self: PBLStringCore; op: UInt32; str: PUTF8Char; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringApplyOpData';
+
+function blStringApplyOpString(self: PBLStringCore; op: UInt32; other: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringApplyOpString';
+
+function blStringApplyOpFormat(self: PBLStringCore; op: UInt32; fmt: PUTF8Char): BLResult varargs; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringApplyOpFormat';
+
+function blStringApplyOpFormatV(self: PBLStringCore; op: UInt32; fmt: PUTF8Char; ap: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringApplyOpFormatV';
+
+function blStringInsertChar(self: PBLStringCore; index: NativeUInt; c: UTF8Char; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringInsertChar';
+
+function blStringInsertData(self: PBLStringCore; index: NativeUInt; str: PUTF8Char; n: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringInsertData';
+
+function blStringInsertString(self: PBLStringCore; index: NativeUInt; other: PBLStringCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringInsertString';
+
+function blStringRemoveRange(self: PBLStringCore; rStart: NativeUInt; rEnd: NativeUInt): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringRemoveRange';
+
+function blStringEquals(self: PBLStringCore; other: PBLStringCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringEquals';
+
+function blStringEqualsData(self: PBLStringCore; str: PUTF8Char; n: NativeUInt): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringEqualsData';
+
+function blStringCompare(self: PBLStringCore; other: PBLStringCore): Integer; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringCompare';
+
+function blStringCompareData(self: PBLStringCore; str: PUTF8Char; n: NativeUInt): Integer; cdecl;
+  external LIB_BLEND2D name _PU + 'blStringCompareData';
+
+
+function blStrokeOptionsInit(self: PBLStrokeOptionsCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStrokeOptionsInit';
+
+function blStrokeOptionsInitMove(self: PBLStrokeOptionsCore; other: PBLStrokeOptionsCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStrokeOptionsInitMove';
+
+function blStrokeOptionsInitWeak(self: PBLStrokeOptionsCore; other: PBLStrokeOptionsCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStrokeOptionsInitWeak';
+
+function blStrokeOptionsDestroy(self: PBLStrokeOptionsCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStrokeOptionsDestroy';
+
+function blStrokeOptionsReset(self: PBLStrokeOptionsCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStrokeOptionsReset';
+
+function blStrokeOptionsAssignMove(self: PBLStrokeOptionsCore; other: PBLStrokeOptionsCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStrokeOptionsAssignMove';
+
+function blStrokeOptionsAssignWeak(self: PBLStrokeOptionsCore; other: PBLStrokeOptionsCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStrokeOptionsAssignWeak';
+
+
+function blStyleInit(self: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleInit';
+
+function blStyleInitMove(self, other: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleInitMove';
+
+function blStyleInitWeak(self, other: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleInitWeak';
+
+function blStyleInitRgba(self: PBLStyleCore; rgba: _PBLRgba): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleInitRgba';
+
+function blStyleInitRgba32(self: PBLStyleCore; rgba: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleInitRgba32';
+
+function blStyleInitRgba64(self: PBLStyleCore; rgba: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleInitRgba64';
+
+function blStyleInitObject(self: PBLStyleCore; &object: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleInitObject';
+
+function blStyleDestroy(self: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleDestroy';
+
+function blStyleReset(self: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleReset';
+
+function blStyleAssignMove(self, other: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleAssignMove';
+
+function blStyleAssignWeak(self, other: PBLStyleCore): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleAssignWeak';
+
+function blStyleAssignRgba(self: PBLStyleCore; rgba: _PBLRgba): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleAssignRgba';
+
+function blStyleAssignRgba32(self: PBLStyleCore; rgba: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleAssignRgba32';
+
+function blStyleAssignRgba64(self: PBLStyleCore; rgba: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleAssignRgba64';
+
+function blStyleAssignObject(self: PBLStyleCore; &object: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleAssignObject';
+
+function blStyleGetType(self: PBLStyleCore): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleGetType';
+
+function blStyleGetRgba(self: PBLStyleCore; rgbaOut: _PBLRgba): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleGetRgba';
+
+function blStyleGetRgba32(self: PBLStyleCore; rgba32Out: UInt32): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleGetRgba32';
+
+function blStyleGetRgba64(self: PBLStyleCore; rgba64Out: UInt64): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleGetRgba64';
+
+function blStyleGetObject(self: PBLStyleCore; &object: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleGetObject';
+
+function blStyleEquals(a, b: PBLStyleCore): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blStyleEquals';
+
+
+function blVariantInit(self: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blVariantInit';
+
+function blVariantInitMove(self: Pointer; other: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blVariantInitMove';
+
+function blVariantInitWeak(self: Pointer; other: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blVariantInitWeak';
+
+function blVariantDestroy(self: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blVariantDestroy';
+
+function blVariantReset(self: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blVariantReset';
+
+function blVariantGetImplType(self: Pointer): UInt32; cdecl;
+  external LIB_BLEND2D name _PU + 'blVariantGetImplType';
+
+function blVariantAssignMove(self: Pointer; other: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blVariantAssignMove';
+
+function blVariantAssignWeak(self: Pointer; other: Pointer): BLResult; cdecl;
+  external LIB_BLEND2D name _PU + 'blVariantAssignWeak';
+
+function blVariantEquals(a: Pointer; b: Pointer): Boolean; cdecl;
+  external LIB_BLEND2D name _PU + 'blVariantEquals';
+
+implementation
+
+function BL_MAKE_TAG(const A, B, C, D: Byte): BLTag; inline;
+begin
+  Result := (A shl 24) or (B shl 16) or (C shl 8) or D;
+end;
+
+end.

+ 17764 - 0
Externals/Graphics32/Examples/Drawing/Benchmark/Blend2D.pas

@@ -0,0 +1,17764 @@
+unit Blend2D;
+{ OPP wrappers for Blend2D C API.
+
+  Follows the C++ API where possible. The following C++ classes are not
+  converted because Delphi provides built-in alternatives for these:
+  * BLArray<T>: uses TArray<T> instead
+  * BLFile: uses TFileStream instead
+  * BLString: uses String instead
+  * BLVariant: not needed
+  * BLStyle: style properties are used in another way. We may introduce a
+    TBLStyle type once Delphi has support for managed records (or use Scope
+    solution like TBLStrokeOptions). }
+
+{$SCOPEDENUMS ON}
+{$EXCESSPRECISION OFF}
+
+interface
+
+uses
+  System.Math,
+  System.SysUtils,
+  Blend2D.Api;
+
+{$REGION 'Error Handling'}
+
+{ ============================================================================
+   [Error Handling - Enums]
+  ============================================================================ }
+
+type
+  { Blend2D result code. }
+  TBLResultCode = (
+    { Successful result code. }
+    Success                   = BL_SUCCESS,
+
+    { Out of memory                 [ENOMEM]. }
+    OutOfMemory               = BL_ERROR_OUT_OF_MEMORY,
+
+    { Invalid value/argument        [EINVAL]. }
+    InvalidValue              = BL_ERROR_INVALID_VALUE,
+
+    { Invalid state                 [EFAULT]. }
+    InvalidState              = BL_ERROR_INVALID_STATE,
+
+    { Invalid handle or file.       [EBADF]. }
+    InvalidHandle             = BL_ERROR_INVALID_HANDLE,
+
+    { Value too large               [EOVERFLOW]. }
+    ValueTooLarge             = BL_ERROR_VALUE_TOO_LARGE,
+
+    { Not initialized (some instance is built-in none when it shouldn't be). }
+    NotInitialized            = BL_ERROR_NOT_INITIALIZED,
+
+    { Not implemented               [ENOSYS]. }
+    NotImplemented            = BL_ERROR_NOT_IMPLEMENTED,
+
+    { Operation not permitted       [EPERM]. }
+    NotPermitted              = BL_ERROR_NOT_PERMITTED,
+
+    { IO error                      [EIO]. }
+    IOError                   = BL_ERROR_IO,
+
+    { Device or resource busy       [EBUSY]. }
+    Busy                      = BL_ERROR_BUSY,
+
+    { Operation interrupted         [EINTR]. }
+    Interrupted               = BL_ERROR_INTERRUPTED,
+
+    { Try again                     [EAGAIN]. }
+    TryAgain                  = BL_ERROR_TRY_AGAIN,
+
+    { Timed out                     [ETIMEDOUT]. }
+    TimedOut                  = BL_ERROR_TIMED_OUT,
+
+    { Broken pipe                   [EPIPE]. }
+    BrokenPipe                = BL_ERROR_BROKEN_PIPE,
+
+    { File is not seekable          [ESPIPE]. }
+    InvalidSeek               = BL_ERROR_INVALID_SEEK,
+
+    { Too many levels of symlinks   [ELOOP]. }
+    SymlinkLoop               = BL_ERROR_SYMLINK_LOOP,
+
+    { File is too large             [EFBIG]. }
+    FileTooLarge              = BL_ERROR_FILE_TOO_LARGE,
+
+    { File/directory already exists [EEXIST]. }
+    AlreadyExists             = BL_ERROR_ALREADY_EXISTS,
+
+    { Access denied                 [EACCES]. }
+    AccessDenied              = BL_ERROR_ACCESS_DENIED,
+
+    { Media changed                 [Windows::ERROR_MEDIA_CHANGED]. }
+    MediaChanged              = BL_ERROR_MEDIA_CHANGED,
+
+    { The file/FS is read-only      [EROFS]. }
+    ReadOnlyFS                = BL_ERROR_READ_ONLY_FS,
+
+    { Device doesn't exist          [ENXIO]. }
+    NoDevice                  = BL_ERROR_NO_DEVICE,
+
+    { Not found, no entry (fs)      [ENOENT]. }
+    NoEntry                   = BL_ERROR_NO_ENTRY,
+
+    { No media in drive/device      [ENOMEDIUM]. }
+    NoMedia                   = BL_ERROR_NO_MEDIA,
+
+    { No more data / end of file    [ENODATA]. }
+    NoMoreData                = BL_ERROR_NO_MORE_DATA,
+
+    { No more files                 [ENMFILE]. }
+    NoMoreFiles               = BL_ERROR_NO_MORE_FILES,
+
+    { No space left on device       [ENOSPC]. }
+    NoSpaceLeft               = BL_ERROR_NO_SPACE_LEFT,
+
+    { Directory is not empty        [ENOTEMPTY]. }
+    NotEmpty                  = BL_ERROR_NOT_EMPTY,
+
+    { Not a file                    [EISDIR]. }
+    NotFile                   = BL_ERROR_NOT_FILE,
+
+    { Not a directory               [ENOTDIR]. }
+    NotDirectory              = BL_ERROR_NOT_DIRECTORY,
+
+    { Not same device               [EXDEV]. }
+    NotSameDevice             = BL_ERROR_NOT_SAME_DEVICE,
+
+    { Not a block device            [ENOTBLK]. }
+    NotBlockDevice            = BL_ERROR_NOT_BLOCK_DEVICE,
+
+    { File/path name is invalid     [n/a]. }
+    InvalidFilename           = BL_ERROR_INVALID_FILE_NAME,
+
+    { File/path name is too long    [ENAMETOOLONG]. }
+    FilenameTooLong           = BL_ERROR_FILE_NAME_TOO_LONG,
+
+    { Too many open files           [EMFILE]. }
+    TooManyOpenFiles          = BL_ERROR_TOO_MANY_OPEN_FILES,
+
+    { Too many open files by OS     [ENFILE]. }
+    TooManyOpenFilesByOS      = BL_ERROR_TOO_MANY_OPEN_FILES_BY_OS,
+
+    { Too many symbolic links on FS [EMLINK]. }
+    TooManyLinks              = BL_ERROR_TOO_MANY_LINKS,
+
+    { Too many threads              [EAGAIN]. }
+    TooManyThreads            = BL_ERROR_TOO_MANY_THREADS,
+
+    { Thread pool is exhausted and couldn't acquire the requested thread count. }
+    ThreadPoolExhausted       = BL_ERROR_THREAD_POOL_EXHAUSTED,
+
+    { File is empty (not specific to any OS error). }
+    FileEmpty                 = BL_ERROR_FILE_EMPTY,
+
+    { File open failed              [Windows::ERROR_OPEN_FAILED]. }
+    OpenFailed                = BL_ERROR_OPEN_FAILED,
+
+    { Not a root device/directory   [Windows::ERROR_DIR_NOT_ROOT]. }
+    NotRootDevice             = BL_ERROR_NOT_ROOT_DEVICE,
+
+    { Unknown system error that failed to translate to Blend2D result code. }
+    UnknownSystemError        = BL_ERROR_UNKNOWN_SYSTEM_ERROR,
+
+    { Invalid data alignment. }
+    InvalidArgument           = BL_ERROR_INVALID_ALIGNMENT,
+
+    { Invalid data signature or header. }
+    InvalidSignature          = BL_ERROR_INVALID_SIGNATURE,
+
+    { Invalid or corrupted data. }
+    InvalidData               = BL_ERROR_INVALID_DATA,
+
+    { Invalid string (invalid data of either UTF8, UTF16, or UTF32). }
+    InvalidString             = BL_ERROR_INVALID_STRING,
+
+    { Truncated data (more data required than memory/stream provides). }
+    DataTruncated             = BL_ERROR_DATA_TRUNCATED,
+
+    { Input data too large to be processed. }
+    DataTooLarge              = BL_ERROR_DATA_TOO_LARGE,
+
+    { Decompression failed due to invalid data (RLE, Huffman, etc). }
+    DecompressionFailed       = BL_ERROR_DECOMPRESSION_FAILED,
+
+    { Invalid geometry (invalid path data or shape). }
+    InvalidGeometry           = BL_ERROR_INVALID_GEOMETRY,
+
+    { Returned when there is no matching vertex in path data. }
+    NoMatchingVertex          = BL_ERROR_NO_MATCHING_VERTEX,
+
+    { No matching cookie (BLContext). }
+    NoMatchingCookie          = BL_ERROR_NO_MATCHING_COOKIE,
+
+    { No states to restore (BLContext). }
+    NoStatesToRestore         = BL_ERROR_NO_STATES_TO_RESTORE,
+
+    { The size of the image is too large. }
+    ImageTooBig               = BL_ERROR_IMAGE_TOO_LARGE,
+
+    { Image codec for a required format doesn't exist. }
+    ImageNoMatchingCodec      = BL_ERROR_IMAGE_NO_MATCHING_CODEC,
+
+    { Unknown or invalid file format that cannot be read. }
+    ImageUnknownFileFormat    = BL_ERROR_IMAGE_UNKNOWN_FILE_FORMAT,
+
+    { Image codec doesn't support reading the file format. }
+    ImageDecoderNotProvided   = BL_ERROR_IMAGE_DECODER_NOT_PROVIDED,
+
+    { Image codec doesn't support writing the file format. }
+    ImageEncoderNotProvided   = BL_ERROR_IMAGE_ENCODER_NOT_PROVIDED,
+
+    { Multiple IHDR chunks are not allowed (PNG). }
+    PngMultipleIHDR           = BL_ERROR_PNG_MULTIPLE_IHDR,
+
+    { Invalid IDAT chunk (PNG). }
+    PngInvalidIDAT            = BL_ERROR_PNG_INVALID_IDAT,
+
+    { Invalid IEND chunk (PNG). }
+    PngInvalidIEND            = BL_ERROR_PNG_INVALID_IEND,
+
+    { Invalid PLTE chunk (PNG). }
+    PngInvalidPLTE            = BL_ERROR_PNG_INVALID_PLTE,
+
+    { Invalid tRNS chunk (PNG). }
+    PngInvalidTRNS            = BL_ERROR_PNG_INVALID_TRNS,
+
+    { Invalid filter type (PNG). }
+    PngInvalidFilter          = BL_ERROR_PNG_INVALID_FILTER,
+
+    { Unsupported feature (JPEG). }
+    JpegUnsupportedFeature    = BL_ERROR_JPEG_UNSUPPORTED_FEATURE,
+
+    { Invalid SOS marker or header (JPEG). }
+    JpegInvalidSOS            = BL_ERROR_JPEG_INVALID_SOS,
+
+    { Invalid SOF marker (JPEG). }
+    JpegInvalidSOF            = BL_ERROR_JPEG_INVALID_SOF,
+
+    { Multiple SOF markers (JPEG). }
+    JpegMultipleSOF           = BL_ERROR_JPEG_MULTIPLE_SOF,
+
+    { Unsupported SOF marker (JPEG). }
+    JpegUnsupportedSOF        = BL_ERROR_JPEG_UNSUPPORTED_SOF,
+
+    { Font doesn't have any data as it's not initialized. }
+    FontNotInitialized        =  BL_ERROR_FONT_NOT_INITIALIZED,
+
+    { Font or font-face was not matched (BLFontManager). }
+    FontNoMatch               = BL_ERROR_FONT_NO_MATCH,
+
+    { Font has no character to glyph mapping data. }
+    FontNoCharacterMapping    = BL_ERROR_FONT_NO_CHARACTER_MAPPING,
+
+    { Font has missing an important table. }
+    FontMissingImportantTable = BL_ERROR_FONT_MISSING_IMPORTANT_TABLE,
+
+    { Font feature is not available. }
+    FontFeatureNotAvailable   = BL_ERROR_FONT_FEATURE_NOT_AVAILABLE,
+
+    { Font has an invalid CFF data. }
+    FontCFFInvalidData        = BL_ERROR_FONT_CFF_INVALID_DATA,
+
+    { Font program terminated because the execution reached the limit. }
+    FontProgramTerminated     = BL_ERROR_FONT_PROGRAM_TERMINATED,
+
+    { Invalid glyph identifier. }
+    InvalidGlyph              = BL_ERROR_INVALID_GLYPH);
+
+type
+  _TBLResultCodeHelper = record helper for TBLResultCode
+  public
+    function ToString: String;
+  end;
+
+{ ============================================================================
+   [Error Handling - Handlers]
+  ============================================================================ }
+
+type
+  { Type of exception that is raised for Blend2D errors.
+    Exceptions are enabled by default, but can be disabled using
+    BLSetErrorHandler. }
+  EBlend2DError = class(Exception)
+  {$REGION 'Internal Declarations'}
+  private
+    FResultCode: TBLResultCode;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create(const AResultCode: TBLResultCode);
+
+    { The Blend2D result code }
+    property ResultCode: TBLResultCode read FResultCode;
+  end;
+
+type
+  { Type of procedure that is called when a Blend2D error occurs.
+
+    Parameters:
+      AResultCode: the Blend2D result code
+      AUserData: any user data passed to BLSetErrorHandler. }
+  TBLErrorHandler = procedure(const AResultCode: TBLResultCode;
+    const AUserData: Pointer);
+
+{ Sets a Blend2D error handler.
+
+  Parameters:
+    AHandler: the error handler that is called when a Blend2D error occurs.
+    AUserData: any data you want to pass to the handler.
+
+  The default error handler raises an exception of type EBlend2DError.
+  You can disable error handling completely by setting AHandler to nil. In that
+  case, there is no way to know if and when an error occured.
+
+  The following procedures can be used to set some default error handlers:
+  * BLSetExceptionErrorHandler: sets the error handler to a procedure that
+    raises an exception when a Blend2D error occurs. This is the default
+    behavior.
+  * BLSetGetLastErrorHandler: sets the error handler to a procedure that sets
+    a global error variable when a Blend2D error occurs. You can then use
+    BLGetLastError to retrieve this error code. }
+procedure BLSetErrorHandler(const AHandler: TBLErrorHandler;
+  const AUserData: Pointer);
+
+{ Sets the error handler to a procedure that raises an exception when a Blend2D
+  error occurs. This is the default behavior. }
+procedure BLSetExceptionErrorHandler;
+
+{ Sets the error handler to a procedure that sets a global error variable when a
+  Blend2D error occurs. You can then use BLGetLastError to retrieve this error
+  code. }
+procedure BLSetGetLastErrorHandler;
+
+{ Retrieves the last Blend2D error, or TBLResultCode.Success if there was
+  none.
+
+  After this call, the last error is reset to TBLResultCode.Success.
+
+  This function should only be used when BLSetGetLastErrorHandler has been
+  called. Otherwise, it always returns TBLResultCode.Success.
+
+  This function is not thread-safe. If Blend2D is used from multiple threads,
+  the returned value can be from any thread. }
+function BLGetLastError: TBLResultCode;
+
+{$ENDREGION 'Error Handling'}
+
+{$REGION 'General'}
+
+{ ============================================================================
+   [General - Types]
+  ============================================================================ }
+
+type
+  { Tag is a 32-bit integer consisting of 4 characters in the following format:
+
+      Tag := (A shl 24) or (B shl 16) or (C shl 8) or D
+
+    Tags are used extensively by OpenType fonts and other binary formats like
+    PNG. In most cases TAGs should only contain ASCII letters, digits, and
+    spaces.
+
+    Blend2D uses TBLTag in public and internal APIs to distinguish between a
+    regular UInt32 and tag. }
+  TBLTag = BLTag;
+
+type
+  { Unique identifier that can be used for caching purposes.
+
+    Some objects such as IBLImage and IBLFontFace have assigned an unique
+    identifier that can be used to identify such objects for caching purposes.
+    This identifier is never zero, so zero can be safely used as "uncached".
+
+    Note: Unique identifier is per-process. It's implemented as an increasing
+    global or thread-local counter in a way that identifiers would not
+    collide. }
+  TBLUniqueId = BLUniqueId;
+
+type
+  { A type used to store a pack of bits.
+    BitWord should be equal in size to a machine word. }
+  TBLBitWord = BLBitWord;
+
+{ ============================================================================
+   [General - Enums]
+  ============================================================================ }
+
+type
+  { Boolean operator. }
+  TBLBooleanOp = (
+    { Result = B. }
+    Copy = BL_BOOLEAN_OP_COPY,
+
+    { Result = A and B. }
+    &And = BL_BOOLEAN_OP_AND,
+
+    { Result = A or B. }
+    &Or  = BL_BOOLEAN_OP_OR,
+
+    { Result = A xor B. }
+    &Xor = BL_BOOLEAN_OP_XOR,
+
+    { Result = A and not B. }
+    Sub  = BL_BOOLEAN_OP_SUB);
+
+type
+  { Extend mode. }
+  TBLExtendMode = (
+    { Pad extend [default]. }
+    Pad              = BL_EXTEND_MODE_PAD,
+
+    { Repeat extend. }
+    &Repeat          = BL_EXTEND_MODE_REPEAT,
+
+    { Reflect extend. }
+    Reflect          = BL_EXTEND_MODE_REFLECT,
+
+    { Alias to Pad. }
+    PadXPadY         = BL_EXTEND_MODE_PAD_X_PAD_Y,
+
+    { Alias to Repeat. }
+    RepeatXRepeatY   = BL_EXTEND_MODE_REPEAT_X_REPEAT_Y,
+
+    { Alias to Reflect. }
+    ReflectXReflectY = BL_EXTEND_MODE_REFLECT_X_REFLECT_Y,
+
+    { Pad X and repeat Y. }
+    PadXRepeatY      = BL_EXTEND_MODE_PAD_X_REPEAT_Y,
+
+    { Pad X and reflect Y. }
+    PadXReflectY     = BL_EXTEND_MODE_PAD_X_REFLECT_Y,
+
+    { Repeat X and pad Y. }
+    RepeatXPadY      = BL_EXTEND_MODE_REPEAT_X_PAD_Y,
+
+    { Repeat X and reflect Y. }
+    RepeatXReflectY  = BL_EXTEND_MODE_REPEAT_X_REFLECT_Y,
+
+    { Reflect X and pad Y. }
+    ReflectXPadY     = BL_EXTEND_MODE_REFLECT_X_PAD_Y,
+
+    { Reflect X and repeat Y. }
+    ReflectXRepeatY  = BL_EXTEND_MODE_REFLECT_X_REPEAT_Y);
+
+type
+  { Text encoding. }
+  TBLTextEncoding = (
+    { UTF-8 encoding. }
+    UTF8   = BL_TEXT_ENCODING_UTF8,
+
+    { UTF-16 encoding (native endian). }
+    UTF16  = BL_TEXT_ENCODING_UTF16,
+
+    { UTF-32 encoding (native endian). }
+    UTF32  = BL_TEXT_ENCODING_UTF32,
+
+    { LATIN1 encoding (one byte per character). }
+    Latin1 = BL_TEXT_ENCODING_LATIN1);
+
+{ ============================================================================
+   [BLRange]
+  ============================================================================ }
+
+type
+  { Provides start and end indexes. It's used to specify a range of an operation
+    related to indexed containers like IBLPath, IBLGradient, etc... }
+  TBLRange = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRange;
+    function GetFinish: Integer; inline;
+    function GetStart: Integer; inline;
+    procedure SetFinish(const AValue: Integer); inline;
+    procedure SetStart(const AValue: Integer); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLRange): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLRange): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AStart, AFinish: Integer); overload; inline;
+    function Equals(const AOther: TBLRange): Boolean; inline;
+
+    property Start: Integer read GetStart write SetStart;
+    property Finish: Integer read GetFinish write SetFinish;
+  end;
+  PBLRange = ^TBLRange;
+
+function BLRange(const AStart, AFinish: Integer): TBLRange; inline;
+
+{$ENDREGION 'General'}
+
+{$REGION 'Array'}
+
+{ ============================================================================
+   [BLArrayView]
+  ============================================================================ }
+
+type
+  { Array view }
+  TBLArrayView<T> = record
+  public type
+    P = ^T;
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLArrayView;
+    function GetLast: Pointer; inline;
+    function GetLength: Integer; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AData: Pointer; const ALength: Integer); overload; inline;
+
+    property Data: Pointer read FHandle.data;
+    property First: Pointer read FHandle.data;
+    property Last: Pointer read GetLast;
+    property Length: Integer read GetLength;
+  end;
+
+{$ENDREGION 'Array'}
+
+{$REGION 'Color'}
+
+{ ============================================================================
+   [BLRgba32]
+  ============================================================================ }
+
+type
+  { 32-bit RGBA color (8-bit per component) stored as $AARRGGBB. }
+  TBLRgba32 = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRgba32;
+    function GetIsOpaque: Boolean; inline;
+    function GetIsTransparent: Boolean; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Implicit(const AValue: Cardinal): TBLRgba32; inline; static;
+    class operator Implicit(const AValue: TBLRgba32): Cardinal; inline; static;
+
+    class operator Equal(const ALeft, ARight: TBLRgba32): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLRgba32): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AValue: Cardinal); overload; inline;
+    procedure Reset(const AR, AG, AB: Byte; const AA: Byte = 255); overload; inline;
+
+    property R: Byte read FHandle.r write FHandle.r;
+    property G: Byte read FHandle.g write FHandle.g;
+    property B: Byte read FHandle.b write FHandle.b;
+    property A: Byte read FHandle.a write FHandle.a;
+    property Value: Cardinal read FHandle.value write FHandle.value;
+
+    property IsOpaque: Boolean read GetIsOpaque;
+    property IsTransparent: Boolean read GetIsTransparent;
+  end;
+  PBLRgba32 = ^TBLRgba32;
+
+function BLRgba32: TBLRgba32; overload; inline;
+function BLRgba32(const AValue: Cardinal): TBLRgba32; overload; inline;
+function BLRgba32(const AR, AG, AB: Byte; const AA: Byte = 255): TBLRgba32; overload; inline;
+
+{ ============================================================================
+   [BLRgba64]
+  ============================================================================ }
+
+type
+  { 64-bit RGBA color (16-bit per component) stored as $AAAARRRRGGGGBBBB. }
+  TBLRgba64 = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRgba64;
+    function GetIsOpaque: Boolean; inline;
+    function GetIsTransparent: Boolean; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Implicit(const AValue: UInt64): TBLRgba64; inline; static;
+    class operator Implicit(const AValue: TBLRgba64): UInt64; inline; static;
+
+    class operator Equal(const ALeft, ARight: TBLRgba64): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLRgba64): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AValue: UInt64); overload; inline;
+    procedure Reset(const AR, AG, AB: Word; const AA: Word = $FFFF); overload; inline;
+    procedure Reset(const AValue: TBLRgba32); overload; inline;
+
+    property R: Word read FHandle.r write FHandle.r;
+    property G: Word read FHandle.g write FHandle.g;
+    property B: Word read FHandle.b write FHandle.b;
+    property A: Word read FHandle.a write FHandle.a;
+    property Value: UInt64 read FHandle.value write FHandle.value;
+
+    property IsOpaque: Boolean read GetIsOpaque;
+    property IsTransparent: Boolean read GetIsTransparent;
+  end;
+  PBLRgba64 = ^TBLRgba64;
+
+function BLRgba64: TBLRgba64; overload; inline;
+function BLRgba64(const AValue: UInt64): TBLRgba64; overload; inline;
+function BLRgba64(const AR, AG, AB: Word; const AA: Word = $FFFF): TBLRgba64; overload; inline;
+function BLRgba64(const AValue: TBLRgba32): TBLRgba64; overload; inline;
+
+{ ============================================================================
+   [BLRgba]
+  ============================================================================ }
+
+type
+  { 128-bit RGBA color stored as 4 32-bit floating point values in [RGBA] order. }
+  TBLRgba = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRgba;
+    function GetIsOpaque: Boolean; inline;
+    function GetIsTransparent: Boolean; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLRgba): Boolean; inline; static;
+    class operator Equal(const ALeft: TBLRgba; const ARight: TBLRgba32): Boolean; inline; static;
+    class operator Equal(const ALeft: TBLRgba; const ARight: TBLRgba64): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLRgba): Boolean; inline; static;
+    class operator NotEqual(const ALeft: TBLRgba; const ARight: TBLRgba32): Boolean; inline; static;
+    class operator NotEqual(const ALeft: TBLRgba; const ARight: TBLRgba64): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AR, AG, AB: Single; const AA: Single = 1); overload; inline;
+    procedure Reset(const ARgba: TBLRgba32); overload; inline;
+    procedure Reset(const ARgba: TBLRgba64); overload; inline;
+
+    property R: Single read FHandle.r write FHandle.r;
+    property G: Single read FHandle.g write FHandle.g;
+    property B: Single read FHandle.b write FHandle.b;
+    property A: Single read FHandle.a write FHandle.a;
+
+    property IsOpaque: Boolean read GetIsOpaque;
+    property IsTransparent: Boolean read GetIsTransparent;
+  end;
+  PBLRgba = ^TBLRgba;
+
+function BLRgba: TBLRgba; overload; inline;
+function BLRgba(const AR, AG, AB: Single; const AA: Single = 1): TBLRgba; overload; inline;
+function BLRgba(const ARgba: TBLRgba32): TBLRgba; overload; inline;
+function BLRgba(const ARgba: TBLRgba64): TBLRgba; overload; inline;
+
+type
+  { Adds TBLRgba32 <-> TBLRgba64 <-> TBLRgba conversion }
+  _TBLRgba32Helper = record helper for TBLRgba32
+  public
+    procedure Reset(const AValue: TBLRgba64); overload; inline;
+    procedure Reset(const AValue: TBLRgba); overload; inline;
+  end;
+
+function BLRgba32(const AValue: TBLRgba64): TBLRgba32; overload; inline;
+function BLRgba32(const AValue: TBLRgba): TBLRgba32; overload; inline;
+
+type
+  { Adds TBLRgba64 <-> TBLRgba conversion }
+  _TBLRgba64Helper = record helper for TBLRgba64
+  public
+    procedure Reset(const AValue: TBLRgba); overload; inline;
+  end;
+
+function BLRgba64(const AValue: TBLRgba): TBLRgba32; overload; inline;
+
+{$ENDREGION 'Color'}
+
+{$REGION 'File System'}
+
+{ ============================================================================
+   [Enums]
+  ============================================================================ }
+
+type
+  { File read flags used by IBLFileSystem.ReadFile. }
+  TBLFileReadFlag = (
+    { Use memory mapping to read the content of the file.
+
+      The destination buffer would be configured to use the memory mapped buffer
+      instead of allocating its own. }
+    MmapEnabled = 0,
+
+    { Avoid memory mapping of small files.
+
+      The size of small file is determined by Blend2D, however, you should
+      expect it to be 16kB or 64kB depending on host operating system. }
+    MmapAvoidSmall = 1,
+
+    { Do not fallback to regular read if memory mapping fails. It's worth noting
+      that memory mapping would fail for files stored on filesystem that is not
+      local (like a mounted network filesystem, etc...). }
+    MmapNoFallback = 3);
+  TBLFileReadFlags = set of TBLFileReadFlag;
+
+{$ENDREGION 'File System'}
+
+{$REGION 'Geometry'}
+
+{ ============================================================================
+   [Enums]
+  ============================================================================ }
+
+type
+  { Direction of a geometry used by geometric primitives and paths. }
+  TBLGeometryDirection = (
+    { No direction specified. }
+    None = BL_GEOMETRY_DIRECTION_NONE,
+
+    { Clockwise direction. }
+    CW   = BL_GEOMETRY_DIRECTION_CW,
+
+    { Counter-clockwise direction. }
+    CCW  = BL_GEOMETRY_DIRECTION_CCW);
+
+type
+  { Geometry type.
+
+    Geometry describes a shape or path that can be either rendered or added to
+    a BLPath container. Both IBLPath and IBLContext provide functionality to
+    work with all geometry types. Please note that each type provided here
+    requires to pass a matching record to the function that consumes
+    AGeometryType and AGeometryData arguments. }
+  TBLGeometryType = (
+    { No geometry provided. }
+    None           = BL_GEOMETRY_TYPE_NONE,
+
+    { TBLBoxI record. }
+    BoxI           = BL_GEOMETRY_TYPE_BOXI,
+
+    { TBLBox record. }
+    BoxD           = BL_GEOMETRY_TYPE_BOXD,
+
+    { TBLRectI record. }
+    RectI          = BL_GEOMETRY_TYPE_RECTI,
+
+    { TBLRect record. }
+    RectD          = BL_GEOMETRY_TYPE_RECTD,
+
+    { TBLCircle record. }
+    Circle         = BL_GEOMETRY_TYPE_CIRCLE,
+
+    { TBLEllipse record. }
+    Ellipse        = BL_GEOMETRY_TYPE_ELLIPSE,
+
+    { TBLRoundRect record. }
+    RoundRect      = BL_GEOMETRY_TYPE_ROUND_RECT,
+
+    { TBLArc record. }
+    Arc            = BL_GEOMETRY_TYPE_ARC,
+
+    { TBLArc record representing chord. }
+    Chord          = BL_GEOMETRY_TYPE_CHORD,
+
+    { TBLArc record representing pie. }
+    Pie            = BL_GEOMETRY_TYPE_PIE,
+
+    { TBLLine record. }
+    Line           = BL_GEOMETRY_TYPE_LINE,
+
+    { TBLTriangle record. }
+    Triangle       = BL_GEOMETRY_TYPE_TRIANGLE,
+
+    { TBLArrayView<TBLPointI> representing a polyline. }
+    PolylineI      = BL_GEOMETRY_TYPE_POLYLINEI,
+
+    { TBLArrayView<TBLPoint> representing a polyline. }
+    PolylineD      = BL_GEOMETRY_TYPE_POLYLINED,
+
+    { TBLArrayView<TBLPointI> representing a polygon. }
+    PolygonI       = BL_GEOMETRY_TYPE_POLYGONI,
+
+    { TBLArrayView<TBLPoint> representing a polygon. }
+    PolygonD       = BL_GEOMETRY_TYPE_POLYGOND,
+
+    { TBLArrayView<TBLBoxI> record. }
+    ArrayViewBoxI  = BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI,
+
+    { TBLArrayView<TBLBox> struct. }
+    ArrayViewBoxD  = BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD,
+
+    { TBLArrayView<TBLRectI> record. }
+    ArrayviewRectI = BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI,
+
+    { TBLArrayView<TBLRect> record. }
+    ArrayViewRectD = BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD,
+
+    { IBLPath. }
+    Path           = BL_GEOMETRY_TYPE_PATH,
+
+    { IBLRegion. }
+    Region         = BL_GEOMETRY_TYPE_REGION,
+
+    { The last simple type. }
+    SimpleLast     = TBLGeometryType.Triangle);
+
+type
+  { Fill rule. }
+  TBLFillRule = (
+    { Non-zero fill-rule. }
+    NonZero = BL_FILL_RULE_NON_ZERO,
+
+    { Even-odd fill-rule. }
+    EvenOdd = BL_FILL_RULE_EVEN_ODD);
+
+type
+  { Hit-test result. }
+  TBLHitTest = (
+    { Fully in. }
+    FullyIn     = BL_HIT_TEST_IN,
+
+    { Partially in/out. }
+    PartiallyIn = BL_HIT_TEST_PART,
+
+    { Fully out. }
+    FullyOut    = BL_HIT_TEST_OUT,
+
+    { Hit test failed (invalid argument, NaNs, etc). }
+    Invalid     = BL_HIT_TEST_INVALID);
+
+{ ============================================================================
+   [BLPointI]
+  ============================================================================ }
+
+type
+  { Point specified as [x, y] using Integer as a storage type. }
+  TBLPointI = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLPointI;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLPointI): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLPointI): Boolean; inline; static;
+
+    class operator Negative(const AValue: TBLPointI): TBLPointI; inline; static;
+
+    class operator Add(const ALeft: TBLPointI; const ARight: Integer): TBLPointI; inline; static;
+    class operator Add(const ALeft: Integer; const ARight: TBLPointI): TBLPointI; inline; static;
+    class operator Add(const ALeft, ARight: TBLPointI): TBLPointI; inline; static;
+
+    class operator Subtract(const ALeft: TBLPointI; const ARight: Integer): TBLPointI; inline; static;
+    class operator Subtract(const ALeft: Integer; const ARight: TBLPointI): TBLPointI; inline; static;
+    class operator Subtract(const ALeft, ARight: TBLPointI): TBLPointI; inline; static;
+
+    class operator Multiply(const ALeft: TBLPointI; const ARight: Integer): TBLPointI; inline; static;
+    class operator Multiply(const ALeft: Integer; const ARight: TBLPointI): TBLPointI; inline; static;
+    class operator Multiply(const ALeft, ARight: TBLPointI): TBLPointI; inline; static;
+
+    class operator IntDivide(const ALeft: TBLPointI; const ARight: Integer): TBLPointI; inline; static;
+    class operator IntDivide(const ALeft: Integer; const ARight: TBLPointI): TBLPointI; inline; static;
+    class operator IntDivide(const ALeft, ARight: TBLPointI): TBLPointI; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX, AY: Integer); overload; inline;
+
+    function Equals(const AOther: TBLPointI): Boolean; inline;
+
+    property X: Integer read FHandle.x write FHandle.x;
+    property Y: Integer read FHandle.y write FHandle.y;
+  end;
+  PBLPointI = ^TBLPointI;
+
+function BLPointI: TBLPointI; overload; inline;
+function BLPointI(const AX, AY: Integer): TBLPointI; overload; inline;
+
+{ ============================================================================
+   [SizeI]
+  ============================================================================ }
+
+type
+  { Size specified as [w, h] using Integer as a storage type. }
+  TBLSizeI = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLSizeI;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLSizeI): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLSizeI): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AW, AH: Integer); overload; inline;
+
+    function Equals(const AOther: TBLSizeI): Boolean; inline;
+
+    property W: Integer read FHandle.w write FHandle.w;
+    property H: Integer read FHandle.h write FHandle.h;
+  end;
+  PBLSizeI = ^TBLSizeI;
+
+function BLSizeI: TBLSizeI; overload; inline;
+function BLSizeI(const AW, AH: Integer): TBLSizeI; overload; inline;
+
+{ ============================================================================
+   [BLBoxI]
+  ============================================================================ }
+
+type
+  { Box specified as [x0, y0, x1, y1] using Integer as a storage type. }
+  TBLBoxI = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLBoxI;
+    function GetHeight: Integer; inline;
+    function GetWidth: Integer; inline;
+    procedure SetHeight(const AValue: Integer); inline;
+    procedure SetWidth(const AValue: Integer); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLBoxI): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLBoxI): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX0, AY0, AX1, AY1: Integer); overload; inline;
+
+    function Equals(const AOther: TBLBoxI): Boolean; inline;
+    function Contains(const AX, AY: Integer): Boolean; overload; inline;
+    function Contains(const AP: TBLPointI): Boolean; overload; inline;
+
+    property X0: Integer read FHandle.x0 write FHandle.x0;
+    property Y0: Integer read FHandle.y0 write FHandle.y0;
+    property X1: Integer read FHandle.x1 write FHandle.x1;
+    property Y1: Integer read FHandle.y1 write FHandle.y1;
+    property Width: Integer read GetWidth write SetWidth;
+    property Height: Integer read GetHeight write SetHeight;
+  end;
+  PBLBoxI = ^TBLBoxI;
+
+function BLBoxI: TBLBoxI; overload; inline;
+function BLBoxI(const AX0, AY0, AX1, AY1: Integer): TBLBoxI; overload; inline;
+
+{ ============================================================================
+   [BLRectI]
+  ============================================================================ }
+
+type
+  { Rectangle specified as [x, y, w, h] using Integer as a storage type. }
+  TBLRectI = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRectI;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLRectI): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLRectI): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX, AY, AW, AH: Integer); overload; inline;
+
+    function Equals(const AOther: TBLRectI): Boolean; inline;
+
+    property X: Integer read FHandle.x write FHandle.x;
+    property Y: Integer read FHandle.y write FHandle.y;
+    property W: Integer read FHandle.w write FHandle.w;
+    property H: Integer read FHandle.h write FHandle.h;
+  end;
+  PBLRectI = ^TBLRectI;
+
+function BLRectI: TBLRectI; overload; inline;
+function BLRectI(const AX, AY, AW, AH: Integer): TBLRectI; overload; inline;
+
+{ ============================================================================
+   [BLPoint]
+  ============================================================================ }
+
+type
+  { Point specified as [x, y] using Double as a storage type. }
+  TBLPoint = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLPoint;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLPoint): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLPoint): Boolean; inline; static;
+
+    class operator Negative(const AValue: TBLPoint): TBLPoint; inline; static;
+
+    class operator Add(const ALeft: TBLPoint; const ARight: Double): TBLPoint; inline; static;
+    class operator Add(const ALeft: Double; const ARight: TBLPoint): TBLPoint; inline; static;
+    class operator Add(const ALeft, ARight: TBLPoint): TBLPoint; inline; static;
+
+    class operator Subtract(const ALeft: TBLPoint; const ARight: Double): TBLPoint; inline; static;
+    class operator Subtract(const ALeft: Double; const ARight: TBLPoint): TBLPoint; inline; static;
+    class operator Subtract(const ALeft, ARight: TBLPoint): TBLPoint; inline; static;
+
+    class operator Multiply(const ALeft: TBLPoint; const ARight: Double): TBLPoint; inline; static;
+    class operator Multiply(const ALeft: Double; const ARight: TBLPoint): TBLPoint; inline; static;
+    class operator Multiply(const ALeft, ARight: TBLPoint): TBLPoint; inline; static;
+
+    class operator Divide(const ALeft: TBLPoint; const ARight: Double): TBLPoint; inline; static;
+    class operator Divide(const ALeft: Double; const ARight: TBLPoint): TBLPoint; inline; static;
+    class operator Divide(const ALeft, ARight: TBLPoint): TBLPoint; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX, AY: Double); overload; inline;
+
+    function Equals(const AOther: TBLPoint): Boolean; inline;
+
+    property X: Double read FHandle.x write FHandle.x;
+    property Y: Double read FHandle.y write FHandle.y;
+  end;
+  PBLPoint = ^TBLPoint;
+
+function BLPoint: TBLPoint; overload; inline;
+function BLPoint(const AX, AY: Double): TBLPoint; overload; inline;
+
+{ ============================================================================
+   [Size]
+  ============================================================================ }
+
+type
+  { Size specified as [w, h] using Double as a storage type. }
+  TBLSize = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLSize;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLSize): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLSize): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AW, AH: Double); overload; inline;
+
+    function Equals(const AOther: TBLSize): Boolean; inline;
+
+    property W: Double read FHandle.w write FHandle.w;
+    property H: Double read FHandle.h write FHandle.h;
+  end;
+  PBLSize = ^TBLSize;
+
+function BLSize: TBLSize; overload; inline;
+function BLSize(const AW, AH: Double): TBLSize; overload; inline;
+
+{ ============================================================================
+   [BLBox]
+  ============================================================================ }
+
+type
+  { Box specified as [x0, y0, x1, y1] using Double as a storage type. }
+  TBLBox = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLBox;
+    function GetWidth: Double; inline;
+    procedure SetWidth(const AValue: Double); inline;
+    function GetHeight: Double; inline;
+    procedure SetHeight(const AValue: Double); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLBox): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLBox): Boolean; inline; static;
+
+    class operator Add(const ALeft: TBLBox; const ARight: Double): TBLBox; inline; static;
+    class operator Add(const ALeft: Double; const ARight: TBLBox): TBLBox; inline; static;
+    class operator Add(const ALeft: TBLBox; const ARight: TBLPoint): TBLBox; inline; static;
+    class operator Add(const ALeft: TBLPoint; const ARight: TBLBox): TBLBox; inline; static;
+
+    class operator Subtract(const ALeft: TBLBox; const ARight: Double): TBLBox; inline; static;
+    class operator Subtract(const ALeft: Double; const ARight: TBLBox): TBLBox; inline; static;
+    class operator Subtract(const ALeft: TBLBox; const ARight: TBLPoint): TBLBox; inline; static;
+    class operator Subtract(const ALeft: TBLPoint; const ARight: TBLBox): TBLBox; inline; static;
+
+    class operator Multiply(const ALeft: TBLBox; const ARight: Double): TBLBox; inline; static;
+    class operator Multiply(const ALeft: Double; const ARight: TBLBox): TBLBox; inline; static;
+    class operator Multiply(const ALeft: TBLBox; const ARight: TBLPoint): TBLBox; inline; static;
+    class operator Multiply(const ALeft: TBLPoint; const ARight: TBLBox): TBLBox; inline; static;
+
+    class operator Divide(const ALeft: TBLBox; const ARight: Double): TBLBox; inline; static;
+    class operator Divide(const ALeft: Double; const ARight: TBLBox): TBLBox; inline; static;
+    class operator Divide(const ALeft: TBLBox; const ARight: TBLPoint): TBLBox; inline; static;
+    class operator Divide(const ALeft: TBLPoint; const ARight: TBLBox): TBLBox; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX0, AY0, AX1, AY1: Double); overload; inline;
+
+    function Equals(const AOther: TBLBox): Boolean; inline;
+    function Contains(const AX, AY: Double): Boolean; overload; inline;
+    function Contains(const AP: TBLPoint): Boolean; overload; inline;
+
+    property X0: Double read FHandle.x0 write FHandle.x0;
+    property Y0: Double read FHandle.y0 write FHandle.y0;
+    property X1: Double read FHandle.x1 write FHandle.x1;
+    property Y1: Double read FHandle.y1 write FHandle.y1;
+    property Width: Double read GetWidth write SetWidth;
+    property Height: Double read GetHeight write SetHeight;
+  end;
+  PBLBox = ^TBLBox;
+
+function BLBox: TBLBox; overload; inline;
+function BLBox(const AX0, AY0, AX1, AY1: Double): TBLBox; overload; inline;
+
+{ ============================================================================
+   [BLRect]
+  ============================================================================ }
+
+type
+  { Rectangle specified as [x, y, w, h] using Double as a storage type. }
+  TBLRect = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRect;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLRect): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLRect): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX, AY, AW, AH: Double); overload; inline;
+
+    function Equals(const AOther: TBLRect): Boolean; inline;
+
+    property X: Double read FHandle.x write FHandle.x;
+    property Y: Double read FHandle.y write FHandle.y;
+    property W: Double read FHandle.w write FHandle.w;
+    property H: Double read FHandle.h write FHandle.h;
+  end;
+  PBLRect = ^TBLRect;
+
+function BLRect: TBLRect; overload; inline;
+function BLRect(const AX, AY, AW, AH: Double): TBLRect; overload; inline;
+
+{ ============================================================================
+   [BLLine]
+  ============================================================================ }
+
+type
+  { Line specified as [x0, y0, x1, y1] using Double as a storage type. }
+  TBLLine = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLLine;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLLine): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLLine): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX0, AY0, AX1, AY1: Double); overload; inline;
+    procedure Reset(const AP0, AP1: TBLPoint); overload; inline;
+
+    function Equals(const AOther: TBLLine): Boolean; inline;
+
+    property X0: Double read FHandle.x0 write FHandle.x0;
+    property Y0: Double read FHandle.y0 write FHandle.y0;
+    property X1: Double read FHandle.x1 write FHandle.x1;
+    property Y1: Double read FHandle.y1 write FHandle.y1;
+  end;
+  PBLLine = ^TBLLine;
+
+function BLLine: TBLLine; overload; inline;
+function BLLine(const AX0, AY0, AX1, AY1: Double): TBLLine; overload; inline;
+function BLLine(const AP0, AP1: TBLPoint): TBLLine; overload; inline;
+
+{ ============================================================================
+   [BLTriangle]
+  ============================================================================ }
+
+type
+  { Triangle data specified as [x0, y0, x1, y1, x2, y2] using Double as a
+    storage type.}
+  TBLTriangle = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLTriangle;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLTriangle): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLTriangle): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX0, AY0, AX1, AY1, AX2, AY2: Double); overload; inline;
+
+    function Equals(const AOther: TBLTriangle): Boolean; inline;
+
+    property X0: Double read FHandle.x0 write FHandle.x0;
+    property Y0: Double read FHandle.y0 write FHandle.y0;
+    property X1: Double read FHandle.x1 write FHandle.x1;
+    property Y1: Double read FHandle.y1 write FHandle.y1;
+    property X2: Double read FHandle.x2 write FHandle.x2;
+    property Y2: Double read FHandle.y2 write FHandle.y2;
+  end;
+  PBLTriangle = ^TBLTriangle;
+
+function BLTriangle: TBLTriangle; overload; inline;
+function BLTriangle(const AX0, AY0, AX1, AY1, AX2, AY2: Double): TBLTriangle; overload; inline;
+
+{ ============================================================================
+   [BLRoundRect]
+  ============================================================================ }
+
+type
+  { Rounded rectangle specified as [x, y, w, h, rx, ry] using Double as a
+    storage type. }
+  TBLRoundRect = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRoundRect;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLRoundRect): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLRoundRect): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const ARect: TBLRect; const AR: Double); overload; inline;
+    procedure Reset(const ARect: TBLRect; const ARX, ARY: Double); overload; inline;
+    procedure Reset(const AX, AY, AW, AH, AR: Double); overload; inline;
+    procedure Reset(const AX, AY, AW, AH, ARX, ARY: Double); overload; inline;
+
+    function Equals(const AOther: TBLRoundRect): Boolean; inline;
+
+    property X: Double read FHandle.x write FHandle.x;
+    property Y: Double read FHandle.y write FHandle.y;
+    property W: Double read FHandle.w write FHandle.w;
+    property H: Double read FHandle.h write FHandle.h;
+  end;
+  PBLRoundRect = ^TBLRoundRect;
+
+function BLRoundRect: TBLRoundRect; overload; inline;
+function BLRoundRect(const ARect: TBLRect; const AR: Double): TBLRoundRect; overload; inline;
+function BLRoundRect(const ARect: TBLRect; const ARX, ARY: Double): TBLRoundRect; overload; inline;
+function BLRoundRect(const AX, AY, AW, AH, AR: Double): TBLRoundRect; overload; inline;
+function BLRoundRect(const AX, AY, AW, AH, ARX, ARY: Double): TBLRoundRect; overload; inline;
+
+{ ============================================================================
+   [BLCircle]
+  ============================================================================ }
+
+type
+  { Circle specified as [cx, cy, r] using Double as a storage type. }
+  TBLCircle = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLCircle;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLCircle): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLCircle): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const ACX, ACY, AR: Double); overload; inline;
+
+    function Equals(const AOther: TBLCircle): Boolean; inline;
+
+    property CX: Double read FHandle.cx write FHandle.cx;
+    property CY: Double read FHandle.cy write FHandle.cy;
+    property R: Double read FHandle.r write FHandle.r;
+  end;
+  PBLCircle = ^TBLCircle;
+
+function BLCircle: TBLCircle; overload; inline;
+function BLCircle(const ACX, ACY, AR: Double): TBLCircle; overload; inline;
+
+{ ============================================================================
+   [BLEllipse]
+  ============================================================================ }
+
+type
+  { Ellipse specified as [cx, cy, rx, dy] using Double as a storage type. }
+  TBLEllipse = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLEllipse;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLEllipse): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLEllipse): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const ACX, ACY, ARX, ARY: Double); overload; inline;
+
+    function Equals(const AOther: TBLEllipse): Boolean; inline;
+
+    property CX: Double read FHandle.cx write FHandle.cx;
+    property CY: Double read FHandle.cy write FHandle.cy;
+    property RX: Double read FHandle.rx write FHandle.rx;
+    property RY: Double read FHandle.ry write FHandle.ry;
+  end;
+  PBLEllipse = ^TBLEllipse;
+
+function BLEllipse: TBLEllipse; overload; inline;
+function BLEllipse(const ACX, ACY, ARX, ARY: Double): TBLEllipse; overload; inline;
+
+{ ============================================================================
+   [BLArc]
+  ============================================================================ }
+
+type
+  { Arc specified as [cx, cy, rx, ry, start, sweep] using Double as a storage
+    type. }
+  TBLArc = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLArc;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLArc): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLArc): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const ACX, ACY, AR, AStart, ASweep: Double); overload; inline;
+    procedure Reset(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload; inline;
+
+    function Equals(const AOther: TBLArc): Boolean; inline;
+
+    property CX: Double read FHandle.cx write FHandle.cx;
+    property CY: Double read FHandle.cy write FHandle.cy;
+    property RX: Double read FHandle.rx write FHandle.rx;
+    property RY: Double read FHandle.ry write FHandle.ry;
+    property Start: Double read FHandle.start write FHandle.start;
+    property Sweep: Double read FHandle.sweep write FHandle.sweep;
+  end;
+  PBLArc = ^TBLArc;
+
+function BLArc: TBLArc; overload; inline;
+function BLArc(const ACX, ACY, AR, AStart, ASweep: Double): TBLArc; overload; inline;
+function BLArc(const ACX, ACY, ARX, ARY, AStart, ASweep: Double): TBLArc; overload; inline;
+
+{ ============================================================================
+   [Globals Functions]
+  ============================================================================ }
+
+function BLAbs(const AA: TBLPoint): TBLPoint; overload; inline;
+function BLAbs(const AA: TBLSize): TBLSize; overload; inline;
+
+function BLMin(const AA, AB: TBLPoint): TBLPoint; overload; inline;
+function BLMin(const AA: TBLPoint; const AB: Double): TBLPoint; overload; inline;
+function BLMin(const AA: Double; const AB: TBLPoint): TBLPoint; overload; inline;
+function BLMin(const AA, AB: TBLSize): TBLSize; overload; inline;
+
+function BLMax(const AA, AB: TBLPoint): TBLPoint; overload; inline;
+function BLMax(const AA: TBLPoint; const AB: Double): TBLPoint; overload; inline;
+function BLMax(const AA: Double; const AB: TBLPoint): TBLPoint; overload; inline;
+function BLMax(const AA, AB: TBLSize): TBLSize; overload; inline;
+
+function BLClamp(const AA: TBLPoint; const AB, AC: Double): TBLPoint; inline;
+
+{$ENDREGION 'Geometry'}
+
+{$REGION 'Matrix'}
+
+{ ============================================================================
+   [BLMatrix2D - Enums]
+  ============================================================================ }
+
+type
+  { 2D matrix type that can be obtained by querying TBLMatrix2D.MatrixType.
+
+    Identity  Transl.  Scale     Swap    Affine
+     [1  0]   [1  0]   [.  0]   [0  .]   [.  .]
+     [0  1]   [0  1]   [0  .]   [.  0]   [.  .]
+     [0  0]   [.  .]   [.  .]   [.  .]   [.  .] }
+  TBLMatrix2DType = (
+    { Identity matrix. }
+    Identity  = BL_MATRIX2D_TYPE_IDENTITY,
+
+    { Has translation part (the rest is like identity). }
+    Translate = BL_MATRIX2D_TYPE_TRANSLATE,
+
+    { Has translation and scaling parts. }
+    Scale     = BL_MATRIX2D_TYPE_SCALE,
+
+    { Has translation and scaling parts, however scaling swaps X/Y. }
+    Swap      = BL_MATRIX2D_TYPE_SWAP,
+
+    { Generic affine matrix. }
+    Affine    = BL_MATRIX2D_TYPE_AFFINE,
+
+    { Invalid/degenerate matrix not useful for transformations. }
+    Invalid   = BL_MATRIX2D_TYPE_INVALID);
+
+type
+  { 2D matrix data index. }
+  TBLMatrix2DValue = (
+    { Value at index 0 - M00. }
+    M00 = BL_MATRIX2D_VALUE_00,
+
+    { Value at index 1 - M01. }
+    M01 = BL_MATRIX2D_VALUE_01,
+
+    { Value at index 2 - M10. }
+    M10 = BL_MATRIX2D_VALUE_10,
+
+    { Value at index 3 - M11. }
+    M11 = BL_MATRIX2D_VALUE_11,
+
+    { Value at index 4 - M20. }
+    M20 = BL_MATRIX2D_VALUE_20,
+
+    { Value at index 5 - M21. }
+    M21 = BL_MATRIX2D_VALUE_21);
+
+{ ============================================================================
+   [BLMatrix2D]
+  ============================================================================ }
+
+type
+  { 2D matrix represents an affine transformation matrix that can be used to
+    transform geometry and images. }
+  TBLMatrix2D = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLMatrix2D;
+    function GetElement(const AIndex: TBLMatrix2DValue): Double; inline;
+    procedure SetElement(const AIndex: TBLMatrix2DValue; const AValue: Double); inline;
+    function GetMatrixType: TBLMatrix2DType; inline;
+    function GetDeterminant: Double; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLMatrix2D): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLMatrix2D): Boolean; inline; static;
+
+    { Creates a new matrix initialized to identity. }
+    class function MakeIdentity: TBLMatrix2D; inline; static;
+
+    { Creates a new matrix initialized to translation. }
+    class function MakeTranslation(const AX, AY: Double): TBLMatrix2D; overload; inline; static;
+    class function MakeTranslation(const AP: TBLPoint): TBLMatrix2D; overload; inline; static;
+    class function MakeTranslation(const AP: TBLPointI): TBLMatrix2D; overload; inline; static;
+
+    { Creates a new matrix initialized to scaling. }
+    class function MakeScaling(const AXY: Double): TBLMatrix2D; overload; inline; static;
+    class function MakeScaling(const AX, AY: Double): TBLMatrix2D; overload; inline; static;
+    class function MakeScaling(const AP: TBLPoint): TBLMatrix2D; overload; inline; static;
+    class function MakeScaling(const AP: TBLPointI): TBLMatrix2D; overload; inline; static;
+
+    { Creates a new matrix initialized to rotation, optional around point. }
+    class function MakeRotation(const AAngle: Double): TBLMatrix2D; overload; inline; static;
+    class function MakeRotation(const AAngle, AX, AY: Double): TBLMatrix2D; overload; inline; static;
+    class function MakeRotation(const AAngle: Double; const AP: TBLPoint): TBLMatrix2D; overload; inline; static;
+
+    { Create a new skewing matrix. }
+    class function MakeSkewing(const AX, AY: Double): TBLMatrix2D; overload; inline; static;
+    class function MakeSkewing(const AP: TBLPoint): TBLMatrix2D; overload; inline; static;
+
+    { Create a new rotation matrix specified by ASin and ACos and optional
+      translation. }
+    class function MakeSinCos(const ASin, ACos: Double; const ATranslateX: Double = 0;
+      const ATranslateY: Double = 0): TBLMatrix2D; overload; inline; static;
+    class function MakeSinCos(const ASin, ACos: Double; const ATranslate: TBLPoint): TBLMatrix2D; overload; inline; static;
+
+    { Inverts ASrc matrix and stores the result in ADst.
+      Returns True if the matrix has been inverted successfully. }
+    class function Invert(const ASrc: TBLMatrix2D; out ADst: TBLMatrix2D): Boolean; overload; inline; static;
+  public
+    { Resets matrix to identity. }
+    procedure Reset; overload; inline;
+
+    { Creates a new matrix initialized to:
+        [m00 m01]
+        [m10 m11]
+        [m20 m21] }
+    procedure Reset(const AM00, AM01, AM10, AM11, AM20, AM21: Double); overload; inline;
+
+    { Resets matrix to translation. }
+    procedure ResetToTranslation(const AX, AY: Double); overload; inline;
+    procedure ResetToTranslation(const AP: TBLPoint); overload; inline;
+    procedure ResetToTranslation(const AP: TBLPointI); overload; inline;
+
+    { Resets matrix to scaling. }
+    procedure ResetToScaling(const AXY: Double); overload; inline;
+    procedure ResetToScaling(const AX, AY: Double); overload; inline;
+    procedure ResetToScaling(const AP: TBLPoint); overload; inline;
+    procedure ResetToScaling(const AP: TBLPointI); overload; inline;
+
+    { Resets matrix to rotation, optional around point. }
+    procedure ResetToRotation(const AAngle: Double); overload;
+    procedure ResetToRotation(const AAngle, AX, AY: Double); overload;
+    procedure ResetToRotation(const AAngle: Double; const AP: TBLPoint); overload;
+
+    { Resets matrix to skewing. }
+    procedure ResetToSkewing(const AX, AY: Double); overload;
+    procedure ResetToSkewing(const AP: TBLPoint); overload;
+
+    { Resets matrix to rotation specified by ASin and ACos and optional
+      translation. }
+    procedure ResetToSinCos(const ASin, ACos: Double; const ATranslateX: Double = 0;
+      const ATranslateY: Double = 0); overload; inline;
+    procedure ResetToSinCos(const ASin, ACos: Double; const ATranslate: TBLPoint); overload; inline;
+
+    function Equals(const AOther: TBLMatrix2D): Boolean; inline;
+
+    procedure Translate(const AX, AY: Double); overload; inline;
+    procedure Translate(const AP: TBLPoint); overload; inline;
+    procedure Translate(const AP: TBLPointI); overload; inline;
+
+    procedure Scale(const AXY: Double); overload; inline;
+    procedure Scale(const AX, AY: Double); overload; inline;
+    procedure Scale(const AP: TBLPoint); overload; inline;
+    procedure Scale(const AP: TBLPointI); overload; inline;
+
+    procedure Rotate(const AAngle: Double); overload;
+    procedure Rotate(const AAngle, AX, AY: Double); overload;
+    procedure Rotate(const AAngle: Double; const AP: TBLPoint); overload;
+
+    procedure Skew(const AX, AY: Double); overload;
+    procedure Skew(const AP: TBLPoint); overload;
+
+    procedure Transform(const AMatrix: TBLMatrix2D);
+
+    procedure PostTranslate(const AX, AY: Double); overload; inline;
+    procedure PostTranslate(const AP: TBLPoint); overload; inline;
+    procedure PostTranslate(const AP: TBLPointI); overload; inline;
+
+    procedure PostScale(const AXY: Double); overload; inline;
+    procedure PostScale(const AX, AY: Double); overload; inline;
+    procedure PostScale(const AP: TBLPoint); overload; inline;
+    procedure PostScale(const AP: TBLPointI); overload; inline;
+
+    procedure PostRotate(const AAngle: Double); overload;
+    procedure PostRotate(const AAngle, AX, AY: Double); overload;
+    procedure PostRotate(const AAngle: Double; const AP: TBLPoint); overload;
+
+    procedure PostSkew(const AX, AY: Double); overload;
+    procedure PostSkew(const AP: TBLPoint); overload;
+
+    procedure PostTransform(const AMatrix: TBLMatrix2D);
+
+    { Inverts the matrix, returns True if the matrix has been inverted
+      successfully. }
+    function Invert: Boolean; overload;
+
+    function MapPoint(const AX, AY: Double): TBLPoint; overload; inline;
+    function MapPoint(const AP: TBLPoint): TBLPoint; overload; inline;
+
+    function MapVector(const AX, AY: Double): TBLPoint; overload; inline;
+    function MapVector(const AV: TBLPoint): TBLPoint; overload; inline;
+
+    property Elements[const AIndex: TBLMatrix2DValue]: Double read GetElement write SetElement; default;
+    property M00: Double read FHandle.m00 write FHandle.m00;
+    property M01: Double read FHandle.m01 write FHandle.m01;
+    property M10: Double read FHandle.m10 write FHandle.m10;
+    property M11: Double read FHandle.m11 write FHandle.m11;
+    property M20: Double read FHandle.m20 write FHandle.m20;
+    property M21: Double read FHandle.m21 write FHandle.m21;
+
+    { The matrix type }
+    property MatrixType: TBLMatrix2DType read GetMatrixType;
+
+    { Calculates the matrix determinant. }
+    property Determinant: Double read GetDeterminant;
+  end;
+  PBLMatrix2D = ^TBLMatrix2D;
+
+function BLMatrix2D: TBLMatrix2D; overload; inline;
+function BLMatrix2D(const AM00, AM01, AM10, AM11, AM20, AM21: Double): TBLMatrix2D; overload; inline;
+
+{$ENDREGION 'Matrix'}
+
+{$REGION 'Random'}
+
+{ ============================================================================
+   [BLRandom]
+  ============================================================================ }
+
+type
+  { Simple pseudo random number generator.
+
+    The current implementation uses a PRNG called `XORSHIFT+`, which has 64-bit
+    seed, 128 bits of state, and full period `2^128 - 1`.
+
+    Based on a paper by Sebastiano Vigna:
+      http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf }
+  TBLRandom = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRandom;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLRandom): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLRandom): Boolean; inline; static;
+  public
+    { Resets the random number generator to the given ASeed. }
+    procedure Reset(const ASeed: UInt64 = 0);
+
+    { Tests whether the random number generator is equivalent to AOther.
+
+      Random number generator would only be equivalent to AOther if it was
+      initialized from the same seed and has the same internal state. }
+    function Equals(const AOther: TBLRandom): Boolean; inline;
+
+    { Returns the next pseudo-random UInt64 value and advances its state. }
+    function NextUInt64: UInt64;
+
+    { Returns the next pseudo-random UInt32 value and advances its state. }
+    function NextUInt32: UInt32;
+
+    { Returns the next pseudo-random Double precision floating point in [0..1)
+      range and advances its state. }
+    function NextDouble: Double;
+  end;
+  PBLRandom = ^TBLRandom;
+
+{$ENDREGION 'Random'}
+
+{$REGION 'Gradient'}
+
+{ ============================================================================
+   [BLGradient - Enums]
+  ============================================================================ }
+
+type
+  { Gradient type. }
+  TBLGradientType = (
+    { Linear gradient type. }
+    Linear  = BL_GRADIENT_TYPE_LINEAR,
+
+    { Radial gradient type. }
+    Radial  = BL_GRADIENT_TYPE_RADIAL,
+
+    { Conical gradient type. }
+    Conical = BL_GRADIENT_TYPE_CONICAL);
+
+type
+  { Gradient data index. }
+  TBLGradientValue = (
+    { x0 - start 'x' for Linear/Radial and center 'x' for Conical. }
+    CommonX0     = BL_GRADIENT_VALUE_COMMON_X0,
+
+    { y0 - start 'y' for Linear/Radial and center 'y' for Conical. }
+    CommonY0     = BL_GRADIENT_VALUE_COMMON_Y0,
+
+    { x1 - end 'x' for Linear/Radial. }
+    CommonX1     = BL_GRADIENT_VALUE_COMMON_X1,
+
+    { y1 - end 'y' for Linear/Radial. }
+    CommonY1     = BL_GRADIENT_VALUE_COMMON_Y1,
+
+    { Radial gradient r0 radius. }
+    RadialR0     = BL_GRADIENT_VALUE_RADIAL_R0,
+
+    {Conical gradient angle. }
+    ConicalAngle = BL_GRADIENT_VALUE_CONICAL_ANGLE);
+
+{ ============================================================================
+   [BLGradientStop]
+  ============================================================================ }
+
+type
+  { Defines an Offset and Rgba color that us used by IBLGradient to define
+    a linear transition between colors. }
+  TBLGradientStop = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLGradientStop;
+    function GetRgba: TBLRgba64; inline;
+    procedure SetRgba(const AValue: TBLRgba64); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLGradientStop): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLGradientStop): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AOffset: Double; const ARgba: TBLRgba32); overload; inline;
+    procedure Reset(const AOffset: Double; const ARgba: TBLRgba64); overload; inline;
+    function Equals(const AOther: TBLGradientStop): Boolean; inline;
+
+    property Offset: Double read FHandle.offset write FHandle.offset;
+    property Rgba: TBLRgba64 read GetRgba write SetRgba;
+  end;
+  PBLGradientStop = ^TBLGradientStop;
+
+function BLGradientStop(const AOffset: Double; const ARgba: TBLRgba32): TBLGradientStop; overload; inline;
+function BLGradientStop(const AOffset: Double; const ARgba: TBLRgba64): TBLGradientStop; overload; inline;
+
+{ ============================================================================
+   [BLLinearGradientValues]
+  ============================================================================ }
+
+type
+  { Linear gradient values packed into a record. }
+  TBLLinearGradientValues = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLLinearGradientValues;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX0, AY0, AX1, AY1: Double); overload; inline;
+
+    property X0: Double read FHandle.x0 write FHandle.x0;
+    property Y0: Double read FHandle.y0 write FHandle.y0;
+    property X1: Double read FHandle.x1 write FHandle.x1;
+    property Y1: Double read FHandle.y1 write FHandle.y1;
+  end;
+  PBLLinearGradientValues = ^TBLLinearGradientValues;
+
+function BLLinearGradientValues(const AX0, AY0, AX1, AY1: Double): TBLLinearGradientValues; inline;
+
+{ ============================================================================
+   [BLRadialGradientValues]
+  ============================================================================ }
+
+type
+  { Radial gradient values packed into a record. }
+  TBLRadialGradientValues = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRadialGradientValues;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX0, AY0, AX1, AY1, AR0: Double); overload; inline;
+
+    property X0: Double read FHandle.x0 write FHandle.x0;
+    property Y0: Double read FHandle.y0 write FHandle.y0;
+    property X1: Double read FHandle.x1 write FHandle.x1;
+    property Y1: Double read FHandle.y1 write FHandle.y1;
+    property R0: Double read FHandle.r0 write FHandle.r0;
+  end;
+  PBLRadialGradientValues = ^TBLRadialGradientValues;
+
+function BLRadialGradientValues(const AX0, AY0, AX1, AY1, AR0: Double): TBLRadialGradientValues; inline;
+
+{ ============================================================================
+   [BLConicalGradientValues]
+  ============================================================================ }
+
+type
+  { Conical gradient values packed into a record. }
+  TBLConicalGradientValues = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLConicalGradientValues;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AX0, AY0, AAngle: Double); overload; inline;
+
+    property X0: Double read FHandle.x0 write FHandle.x0;
+    property Y0: Double read FHandle.y0 write FHandle.y0;
+    property Angle: Double read FHandle.angle write FHandle.angle;
+  end;
+  PBLConicalGradientValues = ^TBLConicalGradientValues;
+
+function BLConicalGradientValues(const AX0, AY0, AAngle: Double): TBLConicalGradientValues; inline;
+
+{ ============================================================================
+   [BLGradient]
+  ============================================================================ }
+
+type
+  { Gradient }
+  IBLGradient = interface
+  ['{804D20E0-8F67-415C-BD26-E56DC3BA4DDC}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetIsEmpty: Boolean;
+    function GetGradientType: TBLGradientType;
+    procedure SetGradientType(const AValue: TBLGradientType);
+    function GetExtendMode: TBLExtendMode;
+    procedure SetExtendMode(const AValue: TBLExtendMode);
+    function GetValue(const AIndex: TBLGradientValue): Double;
+    procedure SetValue(const AIndex: TBLGradientValue; const AValue: Double);
+    function GetLinear: TBLLinearGradientValues;
+    procedure SetLinear(const AValue: TBLLinearGradientValues);
+    function GetRadial: TBLRadialGradientValues;
+    procedure SetRadial(const AValue: TBLRadialGradientValues);
+    function GetConical: TBLConicalGradientValues;
+    procedure SetConical(const AValue: TBLConicalGradientValues);
+    function GetX0: Double;
+    procedure SetX0(const AValue: Double);
+    function GetY0: Double;
+    procedure SetY0(const AValue: Double);
+    function GetX1: Double;
+    procedure SetX1(const AValue: Double);
+    function GetY1: Double;
+    procedure SetY1(const AValue: Double);
+    function GetR0: Double;
+    procedure SetR0(const AValue: Double);
+    function GetAngle: Double;
+    procedure SetAngle(const AValue: Double);
+    function GetSize: Integer;
+    function GetCapacity: Integer;
+    function GetAllStops: PBLGradientStop;
+    function GetStop(const AIndex: Integer): TBLGradientStop;
+    procedure SetStop(const AIndex: Integer; const AValue: TBLGradientStop);
+    function GetHasMatrix: Boolean;
+    function GetMatrixType: TBLMatrix2DType;
+    function GetMatrix: TBLMatrix2D;
+    procedure SetMatrix(const AValue: TBLMatrix2D);
+    function GetHandle: PBLGradientCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    procedure Initialize(const AValues: TBLLinearGradientValues;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.Pad;
+      const AStops: TArray<TBLGradientStop> = nil); overload;
+    procedure Initialize(const AValues: TBLRadialGradientValues;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.Pad;
+      const AStops: TArray<TBLGradientStop> = nil); overload;
+    procedure Initialize(const AValues: TBLConicalGradientValues;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.Pad;
+      const AStops: TArray<TBLGradientStop> = nil); overload;
+
+    procedure Initialize(const AValues: TBLLinearGradientValues;
+      const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+      const AMatrix: TBLMatrix2D); overload;
+    procedure Initialize(const AValues: TBLRadialGradientValues;
+      const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+      const AMatrix: TBLMatrix2D); overload;
+    procedure Initialize(const AValues: TBLConicalGradientValues;
+      const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+      const AMatrix: TBLMatrix2D); overload;
+
+    procedure Reset;
+    function Equals(const AOther: IBLGradient): Boolean;
+
+    { Resets the gradient extend mode to TBLExtendMode.Pad. }
+    procedure ResetExtendMode;
+
+    procedure SetValues(const AIndex: TBLGradientValue; const AValues: TArray<Double>); overload;
+    procedure SetValues(const AValues: TBLLinearGradientValues); overload;
+    procedure SetValues(const AValues: TBLRadialGradientValues); overload;
+    procedure SetValues(const AValues: TBLConicalGradientValues); overload;
+
+    { Reserves the capacity of gradient for at least ACount stops. }
+    procedure Reserve(const ACount: Integer);
+
+    { Shrinks the capacity of gradient stops to fit the current usage. }
+    procedure Shrink;
+
+    procedure ResetStops;
+    procedure SetStops(const AStops: TArray<TBLGradientStop>);
+    procedure AddStop(const AOffset: Double; const ARgba: TBLRgba32); overload;
+    procedure AddStop(const AOffset: Double; const ARgba: TBLRgba64); overload;
+    procedure RemoveStop(const AIndex: Integer);
+    procedure RemoveStopByOffset(const AOffset: Double; const AAll: Boolean = True);
+    procedure RemoveStops(const ARange: TBLRange);
+    procedure RemoveStopsByOffset(const AOffsetMin, AOffsetMax: Double);
+    procedure ReplaceStop(const AIndex: Integer; const AOffset: Double;
+      const ARgba: TBLRgba32); overload;
+    procedure ReplaceStop(const AIndex: Integer; const AOffset: Double;
+      const ARgba: TBLRgba64); overload;
+    function IndexOfStop(const AOffset: Double): Integer;
+
+    procedure ResetMatrix;
+
+    procedure Translate(const AX, AY: Double); overload;
+    procedure Translate(const AP: TBLPoint); overload;
+    procedure Translate(const AP: TBLPointI); overload;
+    procedure Scale(const AXY: Double); overload;
+    procedure Scale(const AX, AY: Double); overload;
+    procedure Scale(const AP: TBLPoint); overload;
+    procedure Scale(const AP: TBLPointI); overload;
+    procedure Skew(const AX, AY: Double); overload;
+    procedure Skew(const AP: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double); overload;
+    procedure Rotate(const AAngle, AX, AY: Double); overload;
+    procedure Rotate(const AAngle: Double; const AP: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double; const AP: TBLPointI); overload;
+    procedure Transform(const AMatrix: TBLMatrix2D);
+
+    procedure PostTranslate(const AX, AY: Double); overload;
+    procedure PostTranslate(const AP: TBLPoint); overload;
+    procedure PostTranslate(const AP: TBLPointI); overload;
+    procedure PostScale(const AXY: Double); overload;
+    procedure PostScale(const AX, AY: Double); overload;
+    procedure PostScale(const AP: TBLPoint); overload;
+    procedure PostScale(const AP: TBLPointI); overload;
+    procedure PostSkew(const AX, AY: Double); overload;
+    procedure PostSkew(const AP: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double); overload;
+    procedure PostRotate(const AAngle, AX, AY: Double); overload;
+    procedure PostRotate(const AAngle: Double; const AP: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double; const AP: TBLPointI); overload;
+    procedure PostTransform(const AMatrix: TBLMatrix2D);
+
+    { Tests whether the gradient path is a built-in nil instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Tests whether the gradient is empty.
+      Empty gradient is considered any gradient that has no stops. }
+    property IsEmpty: Boolean read GetIsEmpty;
+
+    { The type of the gradient }
+    property GradientType: TBLGradientType read GetGradientType write SetGradientType;
+
+    { The gradient extend mode }
+    property ExtendMode: TBLExtendMode read GetExtendMode write SetExtendMode;
+
+    property Values[const AIndex: TBLGradientValue]: Double read GetValue write SetValue;
+
+    property Linear: TBLLinearGradientValues read GetLinear write SetLinear;
+    property Radial: TBLRadialGradientValues read GetRadial write SetRadial;
+    property Conical: TBLConicalGradientValues read GetConical write SetConical;
+
+    property X0: Double read GetX0 write SetX0;
+    property Y0: Double read GetY0 write SetY0;
+    property X1: Double read GetX1 write SetX1;
+    property Y1: Double read GetY1 write SetY1;
+    property R0: Double read GetR0 write SetR0;
+    property Angle: Double read GetAngle write SetAngle;
+
+    { The number of stops the gradient has. }
+    property Size: Integer read GetSize;
+
+    { The gradient capacity [in stops]. }
+    property Capacity: Integer read GetCapacity;
+
+    { The gradient stop data. }
+    property AllStops: PBLGradientStop read GetAllStops;
+
+    { A gradient stop at AIndex. }
+    property Stops[const AIndex: Integer]: TBLGradientStop read GetStop write SetStop;
+
+    property HasMatrix: Boolean read GetHasMatrix;
+    property MatrixType: TBLMatrix2DType read GetMatrixType;
+    property Matrix: TBLMatrix2D read GetMatrix write SetMatrix;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLGradientCore read GetHandle;
+  end;
+
+type
+  { Implements IBLGradient }
+  TBLGradient = class(TInterfacedObject, IBLGradient)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLGradientCore;
+    FIsReference: Boolean;
+  protected
+    { IBLGradient }
+    function GetIsNone: Boolean;
+    function GetIsEmpty: Boolean;
+    function GetGradientType: TBLGradientType;
+    procedure SetGradientType(const AValue: TBLGradientType);
+    function GetExtendMode: TBLExtendMode;
+    procedure SetExtendMode(const AValue: TBLExtendMode);
+    function GetValue(const AIndex: TBLGradientValue): Double;
+    procedure SetValue(const AIndex: TBLGradientValue; const AValue: Double);
+    function GetLinear: TBLLinearGradientValues;
+    procedure SetLinear(const AValue: TBLLinearGradientValues);
+    function GetRadial: TBLRadialGradientValues;
+    procedure SetRadial(const AValue: TBLRadialGradientValues);
+    function GetConical: TBLConicalGradientValues;
+    procedure SetConical(const AValue: TBLConicalGradientValues);
+    function GetX0: Double;
+    procedure SetX0(const AValue: Double);
+    function GetY0: Double;
+    procedure SetY0(const AValue: Double);
+    function GetX1: Double;
+    procedure SetX1(const AValue: Double);
+    function GetY1: Double;
+    procedure SetY1(const AValue: Double);
+    function GetR0: Double;
+    procedure SetR0(const AValue: Double);
+    function GetAngle: Double;
+    procedure SetAngle(const AValue: Double);
+    function GetSize: Integer;
+    function GetCapacity: Integer;
+    function GetAllStops: PBLGradientStop;
+    function GetStop(const AIndex: Integer): TBLGradientStop;
+    procedure SetStop(const AIndex: Integer; const AValue: TBLGradientStop);
+    function GetHasMatrix: Boolean;
+    function GetMatrixType: TBLMatrix2DType;
+    function GetMatrix: TBLMatrix2D;
+    procedure SetMatrix(const AValue: TBLMatrix2D);
+    function GetHandle: PBLGradientCore;
+
+    procedure Initialize(const AValues: TBLLinearGradientValues;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.Pad;
+      const AStops: TArray<TBLGradientStop> = nil); overload;
+    procedure Initialize(const AValues: TBLRadialGradientValues;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.Pad;
+      const AStops: TArray<TBLGradientStop> = nil); overload;
+    procedure Initialize(const AValues: TBLConicalGradientValues;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.Pad;
+      const AStops: TArray<TBLGradientStop> = nil); overload;
+
+    procedure Initialize(const AValues: TBLLinearGradientValues;
+      const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+      const AMatrix: TBLMatrix2D); overload;
+    procedure Initialize(const AValues: TBLRadialGradientValues;
+      const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+      const AMatrix: TBLMatrix2D); overload;
+    procedure Initialize(const AValues: TBLConicalGradientValues;
+      const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+      const AMatrix: TBLMatrix2D); overload;
+
+    procedure Reset;
+    function Equals(const AOther: IBLGradient): Boolean; reintroduce; overload;
+
+    procedure ResetExtendMode;
+
+    procedure SetValues(const AIndex: TBLGradientValue; const AValues: TArray<Double>); overload;
+    procedure SetValues(const AValues: TBLLinearGradientValues); overload;
+    procedure SetValues(const AValues: TBLRadialGradientValues); overload;
+    procedure SetValues(const AValues: TBLConicalGradientValues); overload;
+
+    procedure Reserve(const ACount: Integer);
+
+    procedure Shrink;
+
+    procedure ResetStops;
+    procedure SetStops(const AStops: TArray<TBLGradientStop>);
+    procedure AddStop(const AOffset: Double; const ARgba: TBLRgba32); overload;
+    procedure AddStop(const AOffset: Double; const ARgba: TBLRgba64); overload;
+    procedure RemoveStop(const AIndex: Integer);
+    procedure RemoveStopByOffset(const AOffset: Double; const AAll: Boolean = True);
+    procedure RemoveStops(const ARange: TBLRange);
+    procedure RemoveStopsByOffset(const AOffsetMin, AOffsetMax: Double);
+    procedure ReplaceStop(const AIndex: Integer; const AOffset: Double;
+      const ARgba: TBLRgba32); overload;
+    procedure ReplaceStop(const AIndex: Integer; const AOffset: Double;
+      const ARgba: TBLRgba64); overload;
+    function IndexOfStop(const AOffset: Double): Integer;
+
+    procedure ResetMatrix;
+
+    procedure Translate(const AX, AY: Double); overload;
+    procedure Translate(const AP: TBLPoint); overload;
+    procedure Translate(const AP: TBLPointI); overload;
+    procedure Scale(const AXY: Double); overload;
+    procedure Scale(const AX, AY: Double); overload;
+    procedure Scale(const AP: TBLPoint); overload;
+    procedure Scale(const AP: TBLPointI); overload;
+    procedure Skew(const AX, AY: Double); overload;
+    procedure Skew(const AP: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double); overload;
+    procedure Rotate(const AAngle, AX, AY: Double); overload;
+    procedure Rotate(const AAngle: Double; const AP: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double; const AP: TBLPointI); overload;
+    procedure Transform(const AMatrix: TBLMatrix2D);
+
+    procedure PostTranslate(const AX, AY: Double); overload;
+    procedure PostTranslate(const AP: TBLPoint); overload;
+    procedure PostTranslate(const AP: TBLPointI); overload;
+    procedure PostScale(const AXY: Double); overload;
+    procedure PostScale(const AX, AY: Double); overload;
+    procedure PostScale(const AP: TBLPoint); overload;
+    procedure PostScale(const AP: TBLPointI); overload;
+    procedure PostSkew(const AX, AY: Double); overload;
+    procedure PostSkew(const AP: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double); overload;
+    procedure PostRotate(const AAngle, AX, AY: Double); overload;
+    procedure PostRotate(const AAngle: Double; const AP: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double; const AP: TBLPointI); overload;
+    procedure PostTransform(const AMatrix: TBLMatrix2D);
+  private
+    constructor Create(const AHandle: BLGradientCore;
+      const AIsReference: Boolean); overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create; overload;
+    constructor Create(const AType: TBLGradientType;
+      const AValues: PDouble = nil); overload;
+
+    constructor Create(const AValues: TBLLinearGradientValues;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.Pad;
+      const AStops: TArray<TBLGradientStop> = nil); overload;
+    constructor Create(const AValues: TBLRadialGradientValues;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.Pad;
+      const AStops: TArray<TBLGradientStop> = nil); overload;
+    constructor Create(const AValues: TBLConicalGradientValues;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.Pad;
+      const AStops: TArray<TBLGradientStop> = nil); overload;
+
+    constructor Create(const AValues: TBLLinearGradientValues;
+      const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+      const AMatrix: TBLMatrix2D); overload;
+    constructor Create(const AValues: TBLRadialGradientValues;
+      const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+      const AMatrix: TBLMatrix2D); overload;
+    constructor Create(const AValues: TBLConicalGradientValues;
+      const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+      const AMatrix: TBLMatrix2D); overload;
+
+    destructor Destroy; override;
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+
+{$ENDREGION 'Gradient'}
+
+{$REGION 'Region'}
+
+{ ============================================================================
+   [Enums]
+  ============================================================================ }
+
+type
+  { Region type. }
+  TBLRegionType = (
+    { Region is empty (has no rectangles). }
+    Empty   = BL_REGION_TYPE_EMPTY,
+
+    { Region has one rectangle (rectangular). }
+    Rect    = BL_REGION_TYPE_RECT,
+
+    { Region has more YX sorted rectangles. }
+    Complex = BL_REGION_TYPE_COMPLEX);
+
+{ ============================================================================
+   [BLRegion]
+  ============================================================================ }
+
+type
+  TBLRegionView = TBLArrayView<TBLBoxI>;
+
+type
+  { 2D region.
+    Region is a set of rectangles sorted and coalesced by their Y/X
+    coordinates. }
+  IBLRegion = interface
+  ['{7AFAFA57-1358-490D-A984-4017EE9E3234}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetIsEmpty: Boolean;
+    function GetRegionType: TBLRegionType;
+    function GetIsRect: Boolean;
+    function GetIsComplex: Boolean;
+    function GetSize: Integer;
+    function GetCapacity: Integer;
+    function GetData: PBLBoxI;
+    function GetDataEnd: PBLBoxI;
+    function GetBoundingBox: TBLBoxI;
+    function GetView: TBLRegionView;
+    function GetHandle: PBLRegionCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    procedure Reset;
+    function Clone: IBLRegion;
+
+    { Tests whether this region and the AOther region are equal. }
+    function Equals(const AOther: IBLRegion): Boolean;
+
+    procedure Assign(const ABox: TBLBoxI); overload;
+    procedure Assign(const ABoxes: TArray<TBLBoxI>); overload;
+    procedure Assign(const ABoxes: PBLBoxI; const ACount: Integer); overload;
+
+    procedure Assign(const ARect: TBLRectI); overload;
+    procedure Assign(const ARects: TArray<TBLRectI>); overload;
+    procedure Assign(const ARects: PBLRectI; const ACount: Integer); overload;
+
+    procedure Clear;
+
+    { Reserves at least ACount boxes in this region. }
+    procedure Reserve(const ACount: Integer);
+
+    { Shrinks the region data so it consumes only memory it requires. }
+    procedure Shrink;
+
+    procedure Combine(const ARegion: IBLRegion; const ABooleanOp: TBLBooleanOp); overload;
+    procedure Combine(const ABox: TBLBoxI; const ABooleanOp: TBLBooleanOp); overload;
+
+    { Translates the region by the given point APt.
+
+      Possible overflow will be handled by clipping to a maximum region
+      boundary, so the final region could be smaller than the region before
+      translation. }
+    procedure Translate(const APt: TBLPointI);
+
+    { Translates the region by the given point APt and clip it to the given
+      AClipBox. }
+    procedure TranslateAndClip(const APt: TBLPointI; const AClipBox: TBLBoxI); overload;
+
+    { Intersects the region with AR and clip it to the given AClipBox. }
+    procedure IntersectAndClip(const AR: IBLRegion; const AClipBox: TBLBoxI); overload;
+
+    { Tests if a given point APt or ABox is in region }
+    function HitTest(const APt: TBLPointI): TBLHitTest; overload;
+    function HitTest(const ABox: TBLBoxI): TBLHitTest; overload;
+
+    { Tests whether the region is a built-in nil instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Tests whether the region is empty. }
+    property IsEmpty: Boolean read GetIsEmpty;
+
+    { The type of the region }
+    property RegionType: TBLRegionType read GetRegionType;
+
+    { Tests whether the region is one rectangle. }
+    property IsRect: Boolean read GetIsRect;
+
+    { Tests whether the region is complex. }
+    property IsComplex: Boolean read GetIsComplex;
+
+    { The region size. }
+    property Size: Integer read GetSize;
+
+    { The region capacity. }
+    property Capacity: Integer read GetCapacity;
+
+    { Pointer to the region data. }
+    property Data: PBLBoxI read GetData;
+
+    { Pointer to the end of the region data. }
+    property DataEnd: PBLBoxI read GetDataEnd;
+
+    { The region's bounding box. }
+    property BoundingBox: TBLBoxI read GetBoundingBox;
+
+    { The region data as TBLRegionView. }
+    property View: TBLRegionView read GetView;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLRegionCore read GetHandle;
+  end;
+
+type
+  { Implements IBLRegion }
+  TBLRegion = class(TInterfacedObject, IBLRegion)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRegionCore;
+  protected
+    { IBLRegion }
+    function GetIsNone: Boolean;
+    function GetIsEmpty: Boolean;
+    function GetRegionType: TBLRegionType;
+    function GetIsRect: Boolean;
+    function GetIsComplex: Boolean;
+    function GetSize: Integer;
+    function GetCapacity: Integer;
+    function GetData: PBLBoxI;
+    function GetDataEnd: PBLBoxI;
+    function GetBoundingBox: TBLBoxI;
+    function GetView: TBLRegionView;
+    function GetHandle: PBLRegionCore;
+
+    procedure Reset;
+    function Clone: IBLRegion;
+
+    function Equals(const AOther: IBLRegion): Boolean; reintroduce; overload;
+
+    procedure Assign(const ABox: TBLBoxI); overload;
+    procedure Assign(const ABoxes: TArray<TBLBoxI>); overload;
+    procedure Assign(const ABoxes: PBLBoxI; const ACount: Integer); overload;
+
+    procedure Assign(const ARect: TBLRectI); overload;
+    procedure Assign(const ARects: TArray<TBLRectI>); overload;
+    procedure Assign(const ARects: PBLRectI; const ACount: Integer); overload;
+
+    procedure Clear;
+
+    procedure Reserve(const ACount: Integer);
+    procedure Shrink;
+
+    procedure Combine(const ARegion: IBLRegion; const ABooleanOp: TBLBooleanOp); overload;
+    procedure Combine(const ABox: TBLBoxI; const ABooleanOp: TBLBooleanOp); overload;
+
+    procedure Translate(const APt: TBLPointI); overload;
+    procedure TranslateAndClip(const APt: TBLPointI; const AClipBox: TBLBoxI); overload;
+    procedure IntersectAndClip(const AR: IBLRegion; const AClipBox: TBLBoxI); overload;
+
+    function HitTest(const APt: TBLPointI): TBLHitTest; overload;
+    function HitTest(const ABox: TBLBoxI): TBLHitTest; overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  public
+    class function Combine(const AA, AB: IBLRegion; const ABooleanOp: TBLBooleanOp): IBLRegion; overload; static;
+    class function Combine(const AA: IBLRegion; const AB: TBLBoxI; const ABooleanOp: TBLBooleanOp): IBLRegion; overload; static;
+    class function Combine(const AA: TBLBoxI; const AB: IBLRegion; const ABooleanOp: TBLBooleanOp): IBLRegion; overload; static;
+    class function Combine(const AA, AB: TBLBoxI; const ABooleanOp: TBLBooleanOp): IBLRegion; overload; static;
+
+    class function Translate(const AR: IBLRegion; const APt: TBLPointI): IBLRegion; overload; static;
+    class function TranslateAndClip(const AR: IBLRegion; const APt: TBLPointI;
+      const AClipBox: TBLBoxI): IBLRegion; overload; static;
+    class function IntersectAndClip(const AA, AB: IBLRegion;
+      const AClipBox: TBLBoxI): IBLRegion; overload; static;
+  end;
+
+{$ENDREGION 'Region'}
+
+{$REGION 'Path'}
+
+{ ============================================================================
+   [Enums]
+  ============================================================================ }
+
+type
+  { Path command. }
+  TBLPathCmd = (
+    { Move-to command (starts a new figure). }
+    Move  = BL_PATH_CMD_MOVE,
+
+    { On-path command (interpreted as line-to or the end of a curve). }
+    &On   = BL_PATH_CMD_ON,
+
+    { Quad-to control point. }
+    Quad  = BL_PATH_CMD_QUAD,
+
+    { Cubic-to control point (always used as a pair of commands). }
+    Cubic = BL_PATH_CMD_CUBIC,
+
+    { Close path. }
+    Close = BL_PATH_CMD_CLOSE);
+  PBLPathCmd = ^TBLPathCmd;
+
+type
+  { Path flags. }
+  TBLPathFlag = (
+    { Path is empty (no commands or close commands only). }
+    Empty    = 0,
+
+    { Path contains multiple figures. }
+    Multiple = 1,
+
+    { Path contains quad curves (at least one). }
+    Quads    = 2,
+
+    { Path contains cubic curves (at least one). }
+    Cubics   = 3,
+
+    { Path is invalid. }
+    Invalid  = 30,
+
+    { Flags are dirty (not reflecting the current status). }
+    Dirty    = 31);
+  TBLPathFlags = set of TBLPathFlag;
+
+type
+  { Path reversal mode. }
+  TBLPathReverseMode = (
+    { Reverse each figure and their order as well (default). }
+    Complete = BL_PATH_REVERSE_MODE_COMPLETE,
+
+    { Reverse each figure separately (keeps their order). }
+    Separate = BL_PATH_REVERSE_MODE_SEPARATE);
+
+type
+  { Stroke join type. }
+  TBLStrokeJoin = (
+    { Miter-join possibly clipped at MiterLimit [default]. }
+    MiterClip  = BL_STROKE_JOIN_MITER_CLIP,
+
+    { Miter-join or bevel-join depending on MiterLimit condition. }
+    MiterBevel = BL_STROKE_JOIN_MITER_BEVEL,
+
+    { Miter-join or round-join depending on MiterLimit condition. }
+    MiterRound = BL_STROKE_JOIN_MITER_ROUND,
+
+    { Bevel-join. }
+    Bevel      = BL_STROKE_JOIN_BEVEL,
+
+    { Round-join. }
+    Round      = BL_STROKE_JOIN_ROUND);
+
+type
+  { Position of a stroke-cap. }
+  TBLStrokeCapPosition = (
+    { Start of the path. }
+    Start  = BL_STROKE_CAP_POSITION_START,
+
+    { End of the path. }
+    Finish = BL_STROKE_CAP_POSITION_END);
+
+type
+  { A presentation attribute defining the shape to be used at the end of open
+    subpaths. }
+  TBLStrokeCap = (
+    { Butt cap [default]. }
+    Butt        = BL_STROKE_CAP_BUTT,
+
+    { Square cap. }
+    Square      = BL_STROKE_CAP_SQUARE,
+
+    { Round cap. }
+    Round       = BL_STROKE_CAP_ROUND,
+
+    { Round cap reversed. }
+    RoundRev    = BL_STROKE_CAP_ROUND_REV,
+
+    { Triangle cap. }
+    Triangle    = BL_STROKE_CAP_TRIANGLE,
+
+    { Triangle cap reversed. }
+    TriangleRev = BL_STROKE_CAP_TRIANGLE_REV);
+
+type
+  { Stroke transform order. }
+  TBLStrokeTransformOrder = (
+    { Transform after stroke  => Transform(Stroke(Input)) [default]. }
+    After  = BL_STROKE_TRANSFORM_ORDER_AFTER,
+
+    { Transform before stroke => Stroke(Transform(Input)). }
+    Before = BL_STROKE_TRANSFORM_ORDER_BEFORE);
+
+type
+  { Mode that specifies how curves are approximated to line segments. }
+  TBLFlattenMode = (
+    { Use default mode (decided by Blend2D). }
+    Default   = BL_FLATTEN_MODE_DEFAULT,
+
+    { Recursive subdivision flattening. }
+    Recursive = BL_FLATTEN_MODE_RECURSIVE);
+
+type
+  { Mode that specifies how to construct offset curves. }
+  TBLOffsetMode = (
+    { Use default mode (decided by Blend2D). }
+    Default   = BL_OFFSET_MODE_DEFAULT,
+
+    { Iterative offset construction. }
+    Iterative = BL_OFFSET_MODE_ITERATIVE);
+
+type
+  { TODO : Implement once added to Blend2D }
+  TBLFitFlag = (_);
+  TBLFitFlags = set of TBLFitFlag;
+
+{ ============================================================================
+   [BLApproximationOptions]
+  ============================================================================ }
+
+type
+  { Options used to describe how geometry is approximated.
+
+    This struct cannot be simply zeroed and then passed to functions that accept
+    approximation options. Use BLApproximationOptions.Default to setup defaults
+    and then alter values you want to change. }
+  TBLApproximationOptions = record
+  {$REGION 'Internal Declarations'}
+  private class var
+    FDefault: BLApproximationOptions;
+  private
+    FHandle: BLApproximationOptions;
+    function GetFlattenMode: TBLFlattenMode; inline;
+    function GetOffsetMode: TBLOffsetMode; inline;
+    procedure SetFlattenMode(const AValue: TBLFlattenMode); inline;
+    procedure SetOffsetMode(const AValue: TBLOffsetMode); inline;
+  private
+    class function GetDefault: TBLApproximationOptions; static;
+  public
+    class constructor Create;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    { Specifies how curves are flattened }
+    property FlattenMode: TBLFlattenMode read GetFlattenMode write SetFlattenMode;
+
+    { Specifies how curves are offsetted (used by stroking) }
+    property OffsetMode: TBLOffsetMode read GetOffsetMode write SetOffsetMode;
+
+    { Tolerance used to flatten curves. }
+    property FlattenTolerance: Double read FHandle.flattenTolerance write FHandle.flattenTolerance;
+
+    { Tolerance used to approximatecubic curves qith quadratic curves. }
+    property SimplifyTolerance: Double read FHandle.simplifyTolerance write FHandle.simplifyTolerance;
+
+    { Curve offsetting parameter, exact meaning depends on OffsetMode. }
+    property OffsetParameter: Double read FHandle.offsetParameter write FHandle.offsetParameter;
+
+    { Default approximation options }
+    class property Default: TBLApproximationOptions read GetDefault;
+  end;
+  PBLApproximationOptions = ^TBLApproximationOptions;
+
+{ ============================================================================
+   [BLStrokeOptions]
+  ============================================================================ }
+
+type
+  { Stroke options. }
+  TBLStrokeOptions = record
+  {$REGION 'Internal Declarations'}
+  private type
+    TScope = class(TInterfacedObject)
+    private
+      FHandle: PBLStrokeOptionsCore;
+    public
+      constructor Create(const AHandle: PBLStrokeOptionsCore);
+      destructor Destroy; override;
+    end;
+  private
+    FHandle: BLStrokeOptionsCore;
+    FScope: IInterface;
+    function GetStartCap: TBLStrokeCap; inline;
+    procedure SetStartCap(const AValue: TBLStrokeCap); inline;
+    function GetEndCap: TBLStrokeCap; inline;
+    procedure SetEndCap(const AValue: TBLStrokeCap); inline;
+    function GetJoin: TBLStrokeJoin; inline;
+    procedure SetJoin(const AValue: TBLStrokeJoin); inline;
+    function GetTransformOrder: TBLStrokeTransformOrder; inline;
+    procedure SetTransformOrder(const AValue: TBLStrokeTransformOrder); inline;
+    function GetDashArray: TArray<Double>; inline;
+    procedure SetDashArray(const AValue: TArray<Double>);
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset;
+    procedure SetCaps(const ACap: TBLStrokeCap); overload; inline;
+    procedure SetCaps(const AStartCap, AEndCap: TBLStrokeCap); overload; inline;
+
+    property StartCap: TBLStrokeCap read GetStartCap write SetStartCap;
+    property EndCap: TBLStrokeCap read GetEndCap write SetEndCap;
+    property Join: TBLStrokeJoin read GetJoin write SetJoin;
+    property TransformOrder: TBLStrokeTransformOrder read GetTransformOrder write SetTransformOrder;
+    property Width: Double read FHandle.width write FHandle.width;
+    property MiterLimit: Double read FHandle.miterLimit write FHandle.miterLimit;
+    property DashOffset: Double read FHandle.dashOffset write FHandle.dashOffset;
+    property DashArray: TArray<Double> read GetDashArray write SetDashArray;
+  end;
+  PBLStrokeOptions = ^TBLStrokeOptions;
+
+{ ============================================================================
+   [BLPath - View]
+  ============================================================================ }
+
+type
+  { 2D path view provides pointers to vertex and command data along with their
+    size. }
+  TBLPathView = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLPathView;
+    function GetCommands: PBLPathCmd; inline;
+    function GetVertices: PBLPoint; inline;
+    function GetCount: Integer; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const ACommands: PBLPathCmd; const AVertices: PBLPoint;
+      const ACount: Integer); overload; inline;
+
+    property Commands: PBLPathCmd read GetCommands;
+    property Vertices: PBLPoint read GetVertices;
+    property Count: Integer read GetCount;
+  end;
+  PBLPathView = ^TBLPathView;
+
+function BLPathView(const ACommands: PBLPathCmd; const AVertices: PBLPoint;
+  const ACount: Integer): TBLPathView; inline;
+
+{ ============================================================================
+   [BLPath]
+  ============================================================================ }
+
+type
+  { 2D vector path }
+  IBLPath = interface
+  ['{18B368F9-0E76-4C83-9B21-06CDB127430E}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetIsEmpty: Boolean;
+    function GetCount: Integer;
+    function GetCapacity: Integer;
+    function GetVertexData: PBLPoint;
+    function GetVertexDataEnd: PBLPoint;
+    function GetLastVertex: TBLPoint;
+    function GetCommandData: PBLPathCmd;
+    function GetCommandDataEnd: PBLPathCmd;
+    function GetView: TBLPathView;
+    function GetInfoFlags: TBLPathFlags;
+    function GetControlBox: TBLBox;
+    function GetBoundingBox: TBLBox;
+    function GetFigureRange(const AIndex: Integer): TBLRange;
+    function GetHandle: PBLPathCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    procedure Reset;
+    function Clone: IBLPath;
+
+    { Tests whether this path and the AOther path are equal.
+
+      The equality check is deep. The data of both paths is examined and binary
+      compared (thus a slight difference like -0 and +0 would make the equality
+      check to fail). }
+    function Equals(const AOther: IBLPath): Boolean;
+
+    { Clears the content of the path. }
+    procedure Clear;
+
+    { Shrinks the capacity of the path to fit the current usage. }
+    procedure Shrink;
+
+    { Reserves the capacity of the path for at least ACoount vertices and
+      commands. }
+    procedure Reserve(const ACount: Integer);
+
+    { Sets vertex at AIndex to ACmd and APt.
+      Set APreserve to True to preserve the current command.}
+    procedure SetVertexAt(const AIndex: Integer; const ACmd: TBLPathCmd;
+      const APt: TBLPoint; const APreserve: Boolean = False); overload;
+
+    { Sets vertex at AIndex to ACmd and [AX, AY].
+      Set APreserve to True to preserve the current command.}
+    procedure SetVertexAt(const AIndex: Integer; const ACmd: TBLPathCmd;
+      const AX, AY: Double; const APreserve: Boolean = False); overload;
+
+    { Moves to AP0.
+      Appends TBLPathCmd.Move[AP0] command to the path. }
+    procedure MoveTo(const AP0: TBLPoint); overload;
+
+    { Moves to [AX0, AY0].
+      Appends TBLPathCmd.Move[AX0, AY0] command to the path. }
+    procedure MoveTo(const AX0, AY0: Double); overload;
+
+    { Adds line to AP1.
+      Appends TBLPathCmd.On[AP1] command to the path. }
+    procedure LineTo(const AP1: TBLPoint); overload;
+
+    { Adds line to [AX1, AY1].
+      Appends TBLPathCmd.On[AX1, AY1] command to the path. }
+    procedure LineTo(const AX1, AY1: Double); overload;
+
+    { Adds a polyline (LineTo) of the given APoly array.
+      Appends multiple TBLPathCmd.On[X, Y] commands to the path depending. }
+    procedure PolyTo(const APoly: TArray<TBLPoint>); overload;
+    procedure PolyTo(const APoly: PBLPoint; const ACount: Integer); overload;
+
+    { Adds a quadratic curve to AP1 and AP2.
+      Appends the following commands to the path:
+      * TBLPathCmd.Quad[AP1]
+      * TBLPathCmd.On[AP2]
+
+      Matches SVG 'Q' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands }
+    procedure QuadTo(const AP1, AP2: TBLPoint); overload;
+
+    { Adds a quadratic curve to [AX1, AY1] and [AX2, AY2].
+      Appends the following commands to the path:
+      * TBLPathCmd.Quad[AX1, AY1]
+      * TBLPathCmd.On[AX2, AY2]
+
+      Matches SVG 'Q' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands }
+    procedure QuadTo(const AX1, AY1, AX2, AY2: Double); overload;
+
+    { Adds a cubic curve to AP1, AP2 and AP3.
+      Appends the following commands to the path:
+      * TBLPathCmd.Cubic[AP1]
+      * TBLPathCmd.Cubic[AP2]
+      * TBLPathCmd.On[AP3]
+
+      Matches SVG 'C' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands }
+    procedure CubicTo(const AP1, AP2, AP3: TBLPoint); overload;
+
+    { Adds a cubic curve to [AX1, AY1], [AX2, AY2] and [AX3, AY3].
+      Appends the following commands to the path:
+      * TBLPathCmd.Cubic[AX1, AY1]
+      * TBLPathCmd.Cubic[AX2, AY2]
+      * TBLPathCmd.On[AX3, AY3]
+
+      Matches SVG 'C' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands }
+    procedure CubicTo(const AX1, AY1, AX2, AY2, AX3, AY3: Double); overload;
+
+    { Adds a smooth quadratic curve to AP2, calculating AP1 from last points.
+      Appends the following commands to the path:
+      * TBLPathCmd.Quad[calculated]
+      * TBLPathCmd.On[AP2]
+
+      Matches SVG 'T' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands }
+    procedure SmoothQuadTo(const AP2: TBLPoint); overload;
+
+    { Adds a smooth quadratic curve to [AX2, AY2], calculating [AX1, AY1] from
+      last points.
+      Appends the following commands to the path:
+      * TBLPathCmd.Quad[calculated]
+      * TBLPathCmd.On[AX2, AY2]
+
+      Matches SVG 'T' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands }
+    procedure SmoothQuadTo(const AX2, AY2: Double); overload;
+
+    { Adds a smooth cubic curve to AP2 and AP3, calculating AP1 from last
+      points.
+      Appends the following commands to the path:
+      * TBLPathCmd.Cubic[calculated]
+      * TBLPathCmd.Cubic[AP2]
+      * TBLPathCmd.On[AP3]
+
+      Matches SVG 'S' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands }
+    procedure SmoothCubicTo(const AP2, AP3: TBLPoint); overload;
+
+    { Adds a smooth cubic curve to [AX2, AY2] and [AX3, AY3], calculating
+      [AX1, AY1] from last points.
+      Appends the following commands to the path:
+      * TBLPathCmd.Cubic[calculated]
+      * TBLPathCmd.Cubic[[AX2, AY2]]
+      * TBLPathCmd.On[[AX3, AY3]]
+
+      Matches SVG 'S' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands }
+    procedure SmoothCubicTo(const AX2, AY2, AX3, AY3: Double); overload;
+
+    { Adds an arc to the path.
+
+      The center of the arc is specified by AC and radius by AR. Both AStart
+      and ASweep angles are in radians. If the last vertex doesn't match the
+      start of the arc then a LineTo would be emitted before adding the arc.
+      Pass True in AForceMoveTo to always emit MoveTo at the beginning of the
+      arc, which starts a new figure. }
+    procedure ArcTo(const AC, AR: TBLPoint; const AStart, ASweep: Double;
+      const AForceMoveTo: Boolean = False); overload;
+    procedure ArcTo(const ACX, ACY, ARX, ARY, AStart, ASweep: Double;
+      const AForceMoveTo: Boolean = False); overload;
+
+    { Adds an arc quadrant (90deg) to the path. The first point AP1 specifies
+      the quadrant corner and the last point AP2 specifies the end point. }
+    procedure ArcQuadrantTo(const AP1, AP2: TBLPoint); overload;
+    procedure ArcQuadrantTo(const AX1, AY1, AX2, AY2: Double); overload;
+
+    { Adds an elliptic arc to the path that follows the SVG specification.
+
+      Matches SVG 'A' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands }
+    procedure EllipticArcTo(const ARP: TBLPoint; const AXAxisRotation: Double;
+      const ALargeArcFlag, ASweepFlag: Boolean; const AP1: TBLPoint); overload;
+    procedure EllipticArcTo(const ARX, ARY, AXAxisRotation: Double;
+      const ALargeArcFlag, ASweepFlag: Boolean; const AX1, AY1: Double); overload;
+
+    { Closes the current figure.
+      Appends TBLPathCmd.Close to the path.
+
+      Matches SVG 'Z' path command:
+      https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand }
+    procedure Close;
+
+    { Adds a closed rectangle to the path specified by ABox. }
+    procedure AddBox(const ABox: TBLBoxI;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBox(const ABox: TBLBox;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a closed rectangle to the path specified by [AX0, AY0, AX1, AY1]. }
+    procedure AddBox(const AX0, AY0, AX1, AY1: Double;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a closed rectangle to the path specified by ARect. }
+    procedure AddRect(const ARect: TBLRectI;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRect(const ARect: TBLRect;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a closed rectangle to the path specified by [AX, AY, AW, AH]. }
+    procedure AddRect(const AX, AY, AW, AH: Double;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a geometry to the path. }
+    procedure AddGeometry(const AGeometryType: TBLGeometryType;
+      const AGeometryData: Pointer; const AMatrix: PBLMatrix2D = nil;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW);
+
+    { Adds a closed circle to the path. }
+    procedure AddCircle(const ACircle: TBLCircle;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddCircle(const ACircle: TBLCircle; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a closed ellipse to the path. }
+    procedure AddEllipse(const AEllipse: TBLEllipse;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddEllipse(const AEllipse: TBLEllipse; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a closed rounded ractangle to the path. }
+    procedure AddRoundRect(const ARoundRect: TBLRoundRect;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRoundRect(const ARoundRect: TBLRoundRect; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds an open arc to the path. }
+    procedure AddArc(const AArc: TBLArc;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddArc(const AArc: TBLArc; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a closed chord to the path. }
+    procedure AddChord(const AChord: TBLArc;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddChord(const AChord: TBLArc; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a closed pie to the path. }
+    procedure AddPie(const APie: TBLArc;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPie(const APie: TBLArc; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds an open line to the path. }
+    procedure AddLine(const ALine: TBLLine;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddLine(const ALine: TBLLine; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a closed triangle. }
+    procedure AddTriangle(const ATriangle: TBLTriangle;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddTriangle(const ATriangle: TBLTriangle; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a polyline. }
+    procedure AddPolyline(const APolyline: TBLArrayView<TBLPointI>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: TBLArrayView<TBLPointI>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: PBLPointI; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: PBLPointI; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddPolyline(const APolyline: TBLArrayView<TBLPoint>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: TBLArrayView<TBLPoint>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: PBLPoint; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: PBLPoint; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a polygon. }
+    procedure AddPolygon(const APolygon: TBLArrayView<TBLPointI>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: TBLArrayView<TBLPointI>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: PBLPointI; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: PBLPointI; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddPolygon(const APolygon: TBLArrayView<TBLPoint>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: TBLArrayView<TBLPoint>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: PBLPoint; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: PBLPoint; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds an array of closed boxes. }
+    procedure AddBoxArray(const ABoxes: TBLArrayView<TBLBoxI>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: TBLArrayView<TBLBoxI>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: PBLBoxI; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: PBLBoxI; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddBoxArray(const ABoxes: TBLArrayView<TBLBox>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: TBLArrayView<TBLBox>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: PBLBox; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: PBLBox; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds an array of closed rectangles. }
+    procedure AddRectArray(const ARects: TBLArrayView<TBLRectI>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: TBLArrayView<TBLRectI>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: PBLRectI; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: PBLRectI; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddRectArray(const ARects: TBLArrayView<TBLRect>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: TBLArrayView<TBLRect>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: PBLRect; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: PBLRect; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds a closed region (converted to set of rectangles). }
+    procedure AddRegion(const ARegion: IBLRegion;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRegion(const ARegion: IBLRegion; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    { Adds other APath to this path. }
+    procedure AddPath(const APath: IBLPath); overload;
+
+    { Adds other APath sliced by the given ARange to this path. }
+    procedure AddPath(const APath: IBLPath; const ARange: TBLRange); overload;
+
+    { Adds other APath translated by ATranslate to this path. }
+    procedure AddPath(const APath: IBLPath; const ATranslate: TBLPoint); overload;
+
+    { Adds other APath translated by ATranslate and sliced by the given ARange
+      to this path. }
+    procedure AddPath(const APath: IBLPath; const ARange: TBLRange;
+      const ATranslate: TBLPoint); overload;
+
+    { Adds other APath transformed by AMatrix to this path. }
+    procedure AddPath(const APath: IBLPath; const AMatrix: TBLMatrix2D); overload;
+
+    { Adds other APath transformed by AMatrix and sliced by the given ARange to
+      this path. }
+    procedure AddPath(const APath: IBLPath; const ARange: TBLRange;
+      const AMatrix: TBLMatrix2D); overload;
+
+    { Adds other APath, but reversed. }
+    procedure AddReversedPath(const APath: IBLPath;
+      const AReverseMode: TBLPathReverseMode); overload;
+    procedure AddReversedPath(const APath: IBLPath; const ARange: TBLRange;
+      const AReverseMode: TBLPathReverseMode); overload;
+
+    { Adds a stroke of APath to this path. }
+    procedure AddStrokedPath(const APath: IBLPath;
+      const AStrokeOptions: TBLStrokeOptions;
+      const AApproximationOptions: TBLApproximationOptions); overload;
+    procedure AddStrokedPath(const APath: IBLPath; const ARange: TBLRange;
+      const AStrokeOptions: TBLStrokeOptions;
+      const AApproximationOptions: TBLApproximationOptions); overload;
+
+    { Manipulation }
+    procedure RemoveRange(const ARange: TBLRange);
+
+    { Translates the whole path by AP. }
+    procedure Translate(const AP: TBLPoint); overload;
+
+    { Translates a part of the path specified by the given ARange by AP. }
+    procedure Translate(const ARange: TBLRange; const AP: TBLPoint); overload;
+
+    { Transforms the whole path by AMatrix. }
+    procedure Transform(const AMatrix: TBLMatrix2D); overload;
+
+    { Transforms a part of the path specified by the given ARange by AMatrix. }
+    procedure Transform(const ARange: TBLRange; const AMatrix: TBLMatrix2D); overload;
+
+    { Fits the whole path into the given ARect by taking into account fit flags
+      passed by AFitFlags. }
+    procedure FitTo(const ARect: TBLRect; const AFitFlags: TBLFitFlags = []); overload;
+
+    { Fits a part of the path specified by the given ARange into the given ARect
+      by taking into account fit flags passed by AFitFlags. }
+    procedure FitTo(const ARange: TBLRange; const ARect: TBLRect;
+      const AFitFlags: TBLFitFlags = []); overload;
+
+    function GetClosestVertex(const AP: TBLPoint; const AMaxDistance: Double): Integer; overload;
+    function GetClosestVertex(const AP: TBLPoint; const AMaxDistance: Double;
+      out AActualDistance: Double): Integer; overload;
+
+    { Hit tests the given point AP by respecting the given AFillRule. }
+    function HitTest(const AP: TBLPoint; const AFillRule: TBLFillRule): TBLHitTest;
+
+    { Tests whether the 2D path is a built-in nil instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Tests whether the 2D path is empty (its size equals zero). }
+    property IsEmpty: Boolean read GetIsEmpty;
+
+    { Count of vertices used }
+    property Count: Integer read GetCount;
+
+    { Path capacity (count of allocated vertices) }
+    property Capacity: Integer read GetCapacity;
+
+    { Path's vertex data (read-only). }
+    property VertexData: PBLPoint read GetVertexData;
+
+    { End of path's vertex data (read-only). }
+    property VertexDataEnd: PBLPoint read GetVertexDataEnd;
+
+    { The last vertex of the path. If the very last command of the path is
+      TBLPathCmd.Close then the path will be iterated in reverse order to match
+      the initial vertex of the last figure. }
+    property LastVertex: TBLPoint read GetLastVertex;
+
+    { Path's command data (read-only). }
+    property CommandData: PBLPathCmd read GetCommandData;
+
+    { End of path's command data (read-only). }
+    property CommandDataEnd: PBLPathCmd read GetCommandDataEnd;
+
+    { The path data as a read-only TBLPathView. }
+    property View: TBLPathView read GetView;
+
+    { Update a path information if necessary. }
+    property InfoFlags: TBLPathFlags read GetInfoFlags;
+
+    { The bounding box of all vertices and control points.
+
+      Control box is simply bounds of all vertices the path has without further
+      processing. It contains both on-path and off-path points. Consider using
+      BoundingBox if you need a visual bounding box. }
+    property ControlBox: TBLBox read GetControlBox;
+
+    { The bounding box of all on-path vertices and curve extremas.
+
+      The bounding box could be smaller than a bounding box obtained by
+      ControlBox as it's calculated by merging only start/end points and curves
+      at their extremas (not control points). The resulting bounding box
+      represents a visual bounds of the path. }
+    property BoundingBox: TBLBox read GetBoundingBox;
+
+    { The range describing figures at the given AIndex. }
+    property FigureRanges[const AIndex: Integer]: TBLRange read GetFigureRange;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLPathCore read GetHandle;
+  end;
+
+type
+  { Optional callback that can be used to consume a path data. }
+  TBLPathSinkEvent = function(const APath: IBLPath; const AInfo: Pointer): TBLResultCode of object;
+
+type
+  { Implements IBLPath }
+  TBLPath = class(TInterfacedObject, IBLPath)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLPathCore;
+  protected
+    { IBLPath }
+    function GetIsNone: Boolean;
+    function GetIsEmpty: Boolean;
+    function GetCount: Integer;
+    function GetCapacity: Integer;
+    function GetVertexData: PBLPoint;
+    function GetVertexDataEnd: PBLPoint;
+    function GetLastVertex: TBLPoint;
+    function GetCommandData: PBLPathCmd;
+    function GetCommandDataEnd: PBLPathCmd;
+    function GetView: TBLPathView;
+    function GetInfoFlags: TBLPathFlags;
+    function GetControlBox: TBLBox;
+    function GetBoundingBox: TBLBox;
+    function GetFigureRange(const AIndex: Integer): TBLRange;
+    function GetHandle: PBLPathCore;
+
+    procedure Reset;
+    function Clone: IBLPath;
+    function Equals(const AOther: IBLPath): Boolean; reintroduce; overload;
+
+    procedure Clear;
+    procedure Shrink;
+    procedure Reserve(const ACount: Integer);
+
+    procedure SetVertexAt(const AIndex: Integer; const ACmd: TBLPathCmd;
+      const APt: TBLPoint; const APreserve: Boolean = False); overload;
+    procedure SetVertexAt(const AIndex: Integer; const ACmd: TBLPathCmd;
+      const AX, AY: Double; const APreserve: Boolean = False); overload;
+
+    procedure MoveTo(const AP0: TBLPoint); overload;
+    procedure MoveTo(const AX0, AY0: Double); overload;
+    procedure LineTo(const AP1: TBLPoint); overload;
+    procedure LineTo(const AX1, AY1: Double); overload;
+    procedure PolyTo(const APoly: TArray<TBLPoint>); overload;
+    procedure PolyTo(const APoly: PBLPoint; const ACount: Integer); overload;
+    procedure QuadTo(const AP1, AP2: TBLPoint); overload;
+    procedure QuadTo(const AX1, AY1, AX2, AY2: Double); overload;
+    procedure CubicTo(const AP1, AP2, AP3: TBLPoint); overload;
+    procedure CubicTo(const AX1, AY1, AX2, AY2, AX3, AY3: Double); overload;
+    procedure SmoothQuadTo(const AP2: TBLPoint); overload;
+    procedure SmoothQuadTo(const AX2, AY2: Double); overload;
+    procedure SmoothCubicTo(const AP2, AP3: TBLPoint); overload;
+    procedure SmoothCubicTo(const AX2, AY2, AX3, AY3: Double); overload;
+    procedure ArcTo(const AC, AR: TBLPoint; const AStart, ASweep: Double;
+      const AForceMoveTo: Boolean = False); overload;
+    procedure ArcTo(const ACX, ACY, ARX, ARY, AStart, ASweep: Double;
+      const AForceMoveTo: Boolean = False); overload;
+    procedure ArcQuadrantTo(const AP1, AP2: TBLPoint); overload;
+    procedure ArcQuadrantTo(const AX1, AY1, AX2, AY2: Double); overload;
+    procedure EllipticArcTo(const ARP: TBLPoint; const AXAxisRotation: Double;
+      const ALargeArcFlag, ASweepFlag: Boolean; const AP1: TBLPoint); overload;
+    procedure EllipticArcTo(const ARX, ARY, AXAxisRotation: Double;
+      const ALargeArcFlag, ASweepFlag: Boolean; const AX1, AY1: Double); overload;
+
+    procedure Close;
+
+    procedure AddBox(const ABox: TBLBoxI;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBox(const ABox: TBLBox;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBox(const AX0, AY0, AX1, AY1: Double;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddRect(const ARect: TBLRectI;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRect(const ARect: TBLRect;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRect(const AX, AY, AW, AH: Double;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddGeometry(const AGeometryType: TBLGeometryType;
+      const AGeometryData: Pointer; const AMatrix: PBLMatrix2D = nil;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW);
+
+    procedure AddCircle(const ACircle: TBLCircle;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddCircle(const ACircle: TBLCircle; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddEllipse(const AEllipse: TBLEllipse;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddEllipse(const AEllipse: TBLEllipse; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddRoundRect(const ARoundRect: TBLRoundRect;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRoundRect(const ARoundRect: TBLRoundRect; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddArc(const AArc: TBLArc;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddArc(const AArc: TBLArc; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddChord(const AChord: TBLArc;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddChord(const AChord: TBLArc; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddPie(const APie: TBLArc;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPie(const APie: TBLArc; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddLine(const ALine: TBLLine;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddLine(const ALine: TBLLine; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddTriangle(const ATriangle: TBLTriangle;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddTriangle(const ATriangle: TBLTriangle; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddPolyline(const APolyline: TBLArrayView<TBLPointI>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: TBLArrayView<TBLPointI>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: PBLPointI; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: PBLPointI; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddPolyline(const APolyline: TBLArrayView<TBLPoint>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: TBLArrayView<TBLPoint>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: PBLPoint; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolyline(const APolyline: PBLPoint; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddPolygon(const APolygon: TBLArrayView<TBLPointI>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: TBLArrayView<TBLPointI>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: PBLPointI; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: PBLPointI; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddPolygon(const APolygon: TBLArrayView<TBLPoint>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: TBLArrayView<TBLPoint>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: PBLPoint; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddPolygon(const APolygon: PBLPoint; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddBoxArray(const ABoxes: TBLArrayView<TBLBoxI>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: TBLArrayView<TBLBoxI>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: PBLBoxI; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: PBLBoxI; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddBoxArray(const ABoxes: TBLArrayView<TBLBox>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: TBLArrayView<TBLBox>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: PBLBox; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddBoxArray(const ABoxes: PBLBox; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddRectArray(const ARects: TBLArrayView<TBLRectI>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: TBLArrayView<TBLRectI>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: PBLRectI; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: PBLRectI; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddRectArray(const ARects: TBLArrayView<TBLRect>;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: TBLArrayView<TBLRect>;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: PBLRect; const ACount: Integer;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRectArray(const ARects: PBLRect; const ACount: Integer;
+      const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddRegion(const ARegion: IBLRegion;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+    procedure AddRegion(const ARegion: IBLRegion; const AMatrix: TBLMatrix2D;
+      const ADirection: TBLGeometryDirection = TBLGeometryDirection.CW); overload;
+
+    procedure AddPath(const APath: IBLPath); overload;
+    procedure AddPath(const APath: IBLPath; const ARange: TBLRange); overload;
+    procedure AddPath(const APath: IBLPath; const ATranslate: TBLPoint); overload;
+    procedure AddPath(const APath: IBLPath; const ARange: TBLRange;
+      const ATranslate: TBLPoint); overload;
+    procedure AddPath(const APath: IBLPath; const AMatrix: TBLMatrix2D); overload;
+    procedure AddPath(const APath: IBLPath; const ARange: TBLRange;
+      const AMatrix: TBLMatrix2D); overload;
+
+    procedure AddReversedPath(const APath: IBLPath;
+      const AReverseMode: TBLPathReverseMode); overload;
+    procedure AddReversedPath(const APath: IBLPath; const ARange: TBLRange;
+      const AReverseMode: TBLPathReverseMode); overload;
+
+    procedure AddStrokedPath(const APath: IBLPath;
+      const AStrokeOptions: TBLStrokeOptions;
+      const AApproximationOptions: TBLApproximationOptions); overload;
+    procedure AddStrokedPath(const APath: IBLPath; const ARange: TBLRange;
+      const AStrokeOptions: TBLStrokeOptions;
+      const AApproximationOptions: TBLApproximationOptions); overload;
+
+    procedure RemoveRange(const ARange: TBLRange);
+
+    procedure Translate(const AP: TBLPoint); overload;
+    procedure Translate(const ARange: TBLRange; const AP: TBLPoint); overload;
+    procedure Transform(const AMatrix: TBLMatrix2D); overload;
+    procedure Transform(const ARange: TBLRange; const AMatrix: TBLMatrix2D); overload;
+
+    procedure FitTo(const ARect: TBLRect; const AFitFlags: TBLFitFlags = []); overload;
+    procedure FitTo(const ARange: TBLRange; const ARect: TBLRect;
+      const AFitFlags: TBLFitFlags = []); overload;
+
+    function GetClosestVertex(const AP: TBLPoint; const AMaxDistance: Double): Integer; overload;
+    function GetClosestVertex(const AP: TBLPoint; const AMaxDistance: Double;
+      out AActualDistance: Double): Integer; overload;
+
+    function HitTest(const AP: TBLPoint; const AFillRule: TBLFillRule): TBLHitTest;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+
+{$ENDREGION 'Path'}
+
+{$REGION 'Format'}
+
+{ ============================================================================
+   [Enums]
+  ============================================================================ }
+
+type
+  { Pixel format.
+
+    Compatibility Table
+    -------------------
+
+    +---------------------+---------------------+-----------------------------+
+    | Blend2D Format      | Cairo Format        | QImage::Format              |
+    +---------------------+---------------------+-----------------------------+
+    | BL_FORMAT_PRGB32    | CAIRO_FORMAT_ARGB32 | Format_ARGB32_Premultiplied |
+    | BL_FORMAT_XRGB32    | CAIRO_FORMAT_RGB24  | Format_RGB32                |
+    | BL_FORMAT_A8        | CAIRO_FORMAT_A8     | n/a                         |
+    +---------------------+---------------------+-----------------------------+ }
+  TBLFormat = (
+    { None or invalid pixel format. }
+    None   = BL_FORMAT_NONE,
+
+    { 32-bit premultiplied ARGB pixel format (8-bit components). }
+    PRGB32 = BL_FORMAT_PRGB32,
+
+    { 32-bit (X)RGB pixel format (8-bit components, alpha ignored). }
+    XRGB32 = BL_FORMAT_XRGB32,
+
+    { 8-bit alpha-only pixel format. }
+    A8     = BL_FORMAT_A8);
+
+type
+  { Pixel format flags. }
+  TBLFormatFlag = (
+    { Pixel format provides RGB components. }
+    RGB           = 0,
+
+    { Pixel format provides only alpha component. }
+    Alpha         = 1,
+
+    { Pixel format provides LUM component (and not RGB components). }
+    LUM           = 2,
+
+    { Indexed pixel format the requres a palette (I/O only). }
+    Indexed       = 4,
+
+    { RGB components are premultiplied by alpha component. }
+    Premultiplied = 8,
+
+    { Pixel format doesn't use native byte-order (I/O only). }
+    ByteSwap      = 9,
+
+    { The following flags are only informative. They are part of BLFormatInfo,
+      but doesn't have to be passed to IBLPixelConverter as they can be easily
+      calculated. }
+
+    { Pixel components are byte aligned (all 8bpp). }
+    ByteAligned   = 16,
+
+    { Pixel has some undefined bits that represent no information.
+
+      For example a 32-bit XRGB pixel has 8 undefined bits that are usually set
+      to all ones so the format can be interpreted as premultiplied RGB as well.
+      There are other formats like 16_0555 where the bit has no information and
+      is usually set to zero. Blend2D doesn't rely on the content of such bits. }
+    UndefinedBits = 17,
+
+    { Little-endian format.
+      Note: This is not a real flag that you can test, it's only provided for
+      convenience to define little endian pixel formats. }
+    LittleEndian  = 0,
+
+    { Big-endian format.
+      Note: This is not a real flag that you can test, it's only provided for
+      convenience to define little endian pixel formats. }
+    BigEndian = ByteSwap);
+  TBLFormatFlags = set of TBLFormatFlag;
+
+type
+  _TBLFormatFlagsHelper = record helper for TBLFormatFlags
+  public const
+    { Pixel format provides RGB and Alpha components. }
+    RGBA = [TBLFormatFlag.RGB, TBLFormatFlag.Alpha];
+
+    { Pixel format provides LUM and Alpha components (and not RGB components). }
+    LUMA = [TBLFormatFlag.LUM, TBLFormatFlag.Alpha];
+  end;
+
+{ ============================================================================
+   [BLFormatInfo]
+  ============================================================================ }
+
+type
+  { Provides a detailed information about a pixel format. Use the TBLFormat.Info
+    property to get information of Blend2D native pixel formats. }
+  TBLFormatInfo = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFormatInfo;
+    function GetFlags: TBLFormatFlags; inline;
+    procedure SetFlags(const AValue: TBLFormatFlags); inline;
+    function GetPalette: PBLRgba32; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLFormatInfo): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLFormatInfo): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const ADepth: Integer; const AFlags: TBLFormatFlags;
+      const ARSize, AGSize, ABSize, AASize, ARShift, AGShift, ABShift,
+      AAShift: Byte); overload; inline;
+    procedure SetSizes(const ARSize, AGSize, ABSize, AASize: Byte); inline;
+    procedure SetShifts(const ARShift, AGShift, ABShift, AAShift: Byte); inline;
+
+    { Query Blend2D AFormat and copy it to this format info.
+
+      Raises TBLResultCode.InvalidValue if the format is invalid (and resets
+      this record in that case).
+
+      Note: TBLFormat.None is considered an invalid format, thus if it's passed
+      to Query, a TBLResultCode.InvalidValue error is raised. }
+    procedure Query(const AFormat: TBLFormat);
+
+    { Sanitize this record.
+
+      Sanitizer verifies whether the format is valid and updates the format
+      information about flags to values that Blend2D expects. For example
+      format flags are properly examined and simplified if possible, byte-swap
+      is implicitly performed for formats where a single component matches one
+      byte, etc... }
+    procedure Sanitize;
+
+    property Depth: Integer read FHandle.depth write FHandle.depth;
+    property Flags: TBLFormatFlags read GetFlags write SetFlags;
+    property RedSize: Byte read FHandle.rSize write FHandle.rSize;
+    property GreenSize: Byte read FHandle.gSize write FHandle.gSize;
+    property BlueSize: Byte read FHandle.bSize write FHandle.bSize;
+    property AlphaSize: Byte read FHandle.aSize write FHandle.aSize;
+    property RedShift: Byte read FHandle.rShift write FHandle.rShift;
+    property GreenShift: Byte read FHandle.gShift write FHandle.gShift;
+    property BlueShift: Byte read FHandle.bShift write FHandle.bShift;
+    property AlphaShift: Byte read FHandle.aShift write FHandle.aShift;
+    property Palette: PBLRgba32 read GetPalette;
+  end;
+  PBLFormatInfo = ^TBLFormatInfo;
+
+type
+  { Additional information about pixel formats }
+  _TBLFormatHelper = record helper for TBLFormat
+  {$REGION 'Internal Declarations'}
+  private
+    function GetInfo: TBLFormatInfo;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    { Information about this pixel format }
+    property Info: TBLFormatInfo read GetInfo;
+  end;
+
+{$ENDREGION 'Format'}
+
+{$REGION 'Image'}
+
+{ ============================================================================
+   [BLImage - Enums]
+  ============================================================================ }
+type
+  { Flags used by TBLImageInfo. }
+  TBLImageInfoFlag = (
+    { Progressive mode. }
+    Progressive = 0);
+  TBLImageInfoFlags = set of TBLImageInfoFlag;
+
+{ ============================================================================
+   [BLImage - Info]
+  ============================================================================ }
+
+type
+  { Image information provided by image codecs. }
+  TBLImageInfo = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLImageInfo;
+    function GetCompression: String; inline;
+    function GetDensity: TBLSize; inline;
+    function GetDepth: Integer; inline;
+    function GetFlags: TBLFormatFlags; inline;
+    function GetFormat: String; inline;
+    function GetFrameCount: Integer; inline;
+    function GetPlaneCount: Integer; inline;
+    function GetSize: TBLSizeI; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    { Image size. }
+    property Size: TBLSizeI read GetSize;
+
+    { Pixel density per one meter, can contain fractions. }
+    property Density: TBLSize read GetDensity;
+
+    { Image flags. }
+    property Flags: TBLFormatFlags read GetFlags;
+
+    { Image depth. }
+    property Depth: Integer read GetDepth;
+
+    { Number of planes. }
+    property PlaneCount: Integer read GetPlaneCount;
+
+    { Number of frames (0 = unknown/unspecified). }
+    property FrameCount: Integer read GetFrameCount;
+
+    { Image format (as understood by codec). }
+    property Format: String read GetFormat;
+
+    { Image compression (as understood by codec). }
+    property Compression: String read GetCompression;
+  end;
+  PBLImageInfo = ^TBLImageInfo;
+
+{ ============================================================================
+   [BLImage - Enums]
+  ============================================================================ }
+
+type
+  { Filter type used by IBLImage.Scale. }
+  TBLImageScaleFilter = (
+    { No filter or uninitialized. }
+    None     = BL_IMAGE_SCALE_FILTER_NONE,
+
+    { Nearest neighbor filter (radius 1.0). }
+    Nearest  = BL_IMAGE_SCALE_FILTER_NEAREST,
+
+    { Bilinear filter (radius 1.0). }
+    Bilinear = BL_IMAGE_SCALE_FILTER_BILINEAR,
+
+    { Bicubic filter (radius 2.0). }
+    Bicubic  = BL_IMAGE_SCALE_FILTER_BICUBIC,
+
+    { Bell filter (radius 1.5). }
+    Bell     = BL_IMAGE_SCALE_FILTER_BELL,
+
+    { Gauss filter (radius 2.0). }
+    Gauss    = BL_IMAGE_SCALE_FILTER_GAUSS,
+
+    { Hermite filter (radius 1.0). }
+    Hermite  = BL_IMAGE_SCALE_FILTER_HERMITE,
+
+    { Hanning filter (radius 1.0). }
+    Hanning  = BL_IMAGE_SCALE_FILTER_HANNING,
+
+    { Catrom filter (radius 2.0). }
+    Catrom   = BL_IMAGE_SCALE_FILTER_CATROM,
+
+    { Bessel filter (radius 3.2383). }
+    Bessel   = BL_IMAGE_SCALE_FILTER_BESSEL,
+
+    { Sinc filter (radius 2.0, adjustable through TLImageScaleOptions). }
+    Sinc     = BL_IMAGE_SCALE_FILTER_SINC,
+
+    { Lanczos filter (radius 2.0, adjustable through TBLImageScaleOptions). }
+    Lanczos  = BL_IMAGE_SCALE_FILTER_LANCZOS,
+
+    { Blackman filter (radius 2.0, adjustable through TBLImageScaleOptions). }
+    Blackman = BL_IMAGE_SCALE_FILTER_BLACKMAN,
+
+    { Mitchell filter (radius 2.0, parameters 'b' and 'c' passed through
+      TBLImageScaleOptions). }
+    Mitchell = BL_IMAGE_SCALE_FILTER_MITCHELL,
+
+    { Filter using a user-function, must be passed through
+      TBLImageScaleOptions. }
+    User     = BL_IMAGE_SCALE_FILTER_USER);
+
+{ ============================================================================
+   [BLImage - Typedefs]
+  ============================================================================ }
+
+type
+  { A user function that can be used by IBLImage.Scale. }
+  TBLImageScaleUserFunc = function(const ADst, AArray: PDouble;
+    const ACount: NativeInt; const AData: Pointer): Integer; cdecl;
+
+{ ============================================================================
+   [BLImage - Data]
+  ============================================================================ }
+
+type
+  { Data that describes a raster image. Used by IBLImage. }
+  TBLImageData = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLImageData;
+    function GetFlags: TBLFormatFlags; inline;
+    function GetFormat: TBLFormat; inline;
+    function GetSize: TBLSizeI; inline;
+    procedure SetFlags(const AValue: TBLFormatFlags); inline;
+    procedure SetFormat(const AValue: TBLFormat); inline;
+    procedure SetSize(const AValue: TBLSizeI); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    property PixelData: Pointer read FHandle.pixelData write FHandle.pixelData;
+    property Stride: NativeInt read FHandle.stride write FHandle.stride;
+    property Size: TBLSizeI read GetSize write SetSize;
+    property Format: TBLFormat read GetFormat write SetFormat;
+    property Flags: TBLFormatFlags read GetFlags write SetFlags;
+  end;
+  PBLImageData = ^TBLImageData;
+
+{ ============================================================================
+   [BLImage - ScaleOptions]
+  ============================================================================ }
+
+type
+  { Options that can used to customize image scaling. }
+  TBLImageScaleOptions = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLImageScaleOptions;
+    function GetUserFunc: TBLImageScaleUserFunc; inline;
+    procedure SetUserFunc(const AValue: TBLImageScaleUserFunc); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+    procedure ResetToDefaults; inline;
+
+    property UserFunc: TBLImageScaleUserFunc read GetUserFunc write SetUserFunc;
+    property UserData: Pointer read FHandle.userData write FHandle.userData;
+    property Radius: Double read FHandle.radius write FHandle.radius;
+    property MitchellB: Double read FHandle.mitchell.b write FHandle.mitchell.b;
+    property MitchellC: Double read FHandle.mitchell.c write FHandle.mitchell.c;
+  end;
+  PBLImageScaleOptions = ^TBLImageScaleOptions;
+
+type
+  IBLImage = interface;
+  IBLImageCodec = interface;
+
+  { This event is called when IBLImage.InitializeFromData is used and the image
+    is destroyed. }
+  TBLImageDestroyEvent = procedure (const AImage: IBLImage) of object;
+
+  { 2D raster image }
+  IBLImage = interface
+  ['{9E756ED1-76AB-4318-92BD-F6D7F14447A5}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetIsEmpty: Boolean;
+    function GetWidth: Integer;
+    function GetHeight: Integer;
+    function GetSize: TBLSizeI;
+    function GetFormat: TBLFormat;
+    function GetHandle: PBLImageCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    { Initializes a new image of a specified width, height, and format. }
+    procedure Initialize(const AWidth, AHeight: Integer;
+      const AFormat: TBLFormat = TBLFormat.PRGB32);
+
+    { Initializes a new image from external data.
+      The pixel data is *not* copied and must stay alive as long as the image
+      is alive. Use AOnDestroy to get notified when the image is destroyed and
+      you can safely free the pixel data. }
+    procedure InitializeFromData(const AWidth, AHeight: Integer;
+      const AFormat: TBLFormat; const APixelData: Pointer;
+      const AStride: Integer; const AOnDestroy: TBLImageDestroyEvent = nil);
+
+    procedure Reset;
+    function Clone: IBLImage;
+    function Equals(const AOther: IBLImage): Boolean;
+    procedure GetData(out AData: TBLImageData);
+    procedure MakeMutable; overload;
+    procedure MakeMutable(out AData: TBLImageData); overload;
+    procedure Convert(const AFormat: TBLFormat);
+    procedure ScaleTo(const ADest: IBLImage; const ASize: TBLSizeI;
+      const AFilter: TBLImageScaleFilter); overload;
+    procedure ScaleTo(const ADest: IBLImage; const ASize: TBLSizeI;
+      const AFilter: TBLImageScaleFilter; const AOptions: TBLImageScaleOptions); overload;
+
+    procedure ReadFromFile(const AFilename: String); overload;
+    procedure ReadFromFile(const AFilename: String;
+      const ACodecs: TArray<IBLImageCodec>); overload;
+
+    procedure ReadFromData(const AData: Pointer; const ASize: Integer); overload;
+    procedure ReadFromData(const AData: Pointer; const ASize: Integer;
+      const ACodecs: TArray<IBLImageCodec>); overload;
+    procedure ReadFromData(const AData: TBytes); overload;
+    procedure ReadFromData(const AData: TBytes;
+      const ACodecs: TArray<IBLImageCodec>); overload;
+    procedure ReadFromData(const AView: TBLArrayView<Byte>); overload;
+    procedure ReadFromData(const AView: TBLArrayView<Byte>;
+      const ACodecs: TArray<IBLImageCodec>); overload;
+
+    procedure WriteToFile(const AFilename: String); overload;
+    procedure WriteToFile(const AFilename: String; const ACodec: IBLImageCodec); overload;
+    function WriteToData(const ACodec: IBLImageCodec): TBytes;
+
+    { Tests whether the image is a built-in nil instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Tests whether the image is empty (has no size). }
+    property IsEmpty: Boolean read GetIsEmpty;
+
+    { Image width. }
+    property Width: Integer read GetWidth;
+
+    { Image height. }
+    property Height: Integer read GetHeight;
+
+    { Image size. }
+    property Size: TBLSizeI read GetSize;
+
+    { Image format. }
+    property Format: TBLFormat read GetFormat;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLImageCore read GetHandle;
+  end;
+
+  { Implements IBLImage }
+  TBLImage = class(TInterfacedObject, IBLImage)
+  {$REGION 'Internal Declarations'}
+  private type
+    TDestroyData = record
+      Image: IBLImage;
+      Event: TBLImageDestroyEvent;
+    end;
+    PDestroyData = ^TDestroyData;
+  private
+    FHandle: BLImageCore;
+    FIsReference: Boolean;
+  private
+    class procedure DoDestroy(impl, destroyData: Pointer); cdecl; static;
+  protected
+    { IBLImage }
+    function GetIsNone: Boolean;
+    function GetIsEmpty: Boolean;
+    function GetWidth: Integer;
+    function GetHeight: Integer;
+    function GetSize: TBLSizeI;
+    function GetFormat: TBLFormat;
+    function GetHandle: PBLImageCore;
+
+    procedure Initialize(const AWidth, AHeight: Integer;
+      const AFormat: TBLFormat);
+
+    procedure InitializeFromData(const AWidth, AHeight: Integer;
+      const AFormat: TBLFormat; const APixelData: Pointer;
+      const AStride: Integer; const AOnDestroy: TBLImageDestroyEvent);
+
+    procedure Reset;
+    function Clone: IBLImage;
+    function Equals(const AOther: IBLImage): Boolean; reintroduce; overload;
+    procedure GetData(out AData: TBLImageData);
+    procedure MakeMutable; overload;
+    procedure MakeMutable(out AData: TBLImageData); overload;
+    procedure Convert(const AFormat: TBLFormat);
+    procedure ScaleTo(const ADest: IBLImage; const ASize: TBLSizeI;
+      const AFilter: TBLImageScaleFilter); overload;
+    procedure ScaleTo(const ADest: IBLImage; const ASize: TBLSizeI;
+      const AFilter: TBLImageScaleFilter; const AOptions: TBLImageScaleOptions); overload;
+
+    procedure ReadFromFile(const AFilename: String); overload;
+    procedure ReadFromFile(const AFilename: String;
+      const ACodecs: TArray<IBLImageCodec>); overload;
+
+    procedure ReadFromData(const AData: Pointer; const ASize: Integer); overload;
+    procedure ReadFromData(const AData: Pointer; const ASize: Integer;
+      const ACodecs: TArray<IBLImageCodec>); overload;
+    procedure ReadFromData(const AData: TBytes); overload;
+    procedure ReadFromData(const AData: TBytes;
+      const ACodecs: TArray<IBLImageCodec>); overload;
+    procedure ReadFromData(const AView: TBLArrayView<Byte>); overload;
+    procedure ReadFromData(const AView: TBLArrayView<Byte>;
+      const ACodecs: TArray<IBLImageCodec>); overload;
+
+    procedure WriteToFile(const AFilename: String); overload;
+    procedure WriteToFile(const AFilename: String; const ACodec: IBLImageCodec); overload;
+    function WriteToData(const ACodec: IBLImageCodec): TBytes;
+  private
+    constructor Create(const AHandle: BLImageCore; const AIsReference: Boolean); overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create; overload;
+    constructor Create(const AWidth, AHeight: Integer;
+      const AFormat: TBLFormat = TBLFormat.PRGB32); overload;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+    class procedure Scale(const ASrc, ADst: IBLImage; const ASize: TBLSizeI;
+      const AFilter: TBLImageScaleFilter); overload; static;
+    class procedure Scale(const ASrc, ADst: IBLImage; const ASize: TBLSizeI;
+      const AFilter: TBLImageScaleFilter; const AOptions: TBLImageScaleOptions); overload; static;
+  end;
+
+{$ENDREGION 'Image'}
+
+{$REGION 'Image Codec'}
+
+{ ============================================================================
+   [BLImageCodec - Enums]
+  ============================================================================ }
+
+  { Image codec feature bits. }
+  TBLImageCodecFeature = (
+    { Image codec supports reading images (can create IBLImageDecoder). }
+    Read       = 0,
+
+    { Image codec supports writing images (can create IBLImageEncoder). }
+    Write      = 1,
+
+    { Image codec supports lossless compression. }
+    Lossless   = 2,
+
+    { Image codec supports lossy compression. }
+    Lossy      = 3,
+
+    { Image codec supports writing multiple frames (GIF). }
+    MultiFrame = 4,
+
+    { Image codec supports IPTC metadata. }
+    IPTC       = 28,
+
+    { Image codec supports EXIF metadata. }
+    EXIF       = 29,
+
+    { Image codec supports XMP metadata. }
+    XMP        = 30);
+  TBLImageCodecFeatures = set of TBLImageCodecFeature;
+
+{ ============================================================================
+   [BLImageDecoder]
+  ============================================================================ }
+
+  { Image decoder }
+  IBLImageDecoder = interface
+  ['{D68437C2-E6EF-46F1-9191-28F844EF17C6}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetLastResult: TBLResultCode;
+    function GetFrameIndex: Integer;
+    function GetBufferIndex: NativeInt;
+    function GetHandle: PBLImageDecoderCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    procedure Reset;
+    function Equals(const AOther: IBLImageDecoder): Boolean;
+
+    procedure Restart;
+
+    procedure ReadInfo(const ABuffer: TBytes; out AInfo: TBLImageInfo); overload;
+    procedure ReadInfo(const ABuffer: TBLArrayView<Byte>; out AInfo: TBLImageInfo); overload;
+    procedure ReadInfo(const ABuffer: Pointer; const ASize: Integer; out AInfo: TBLImageInfo); overload;
+
+    function ReadFrame(const ABuffer: TBytes): IBLImage; overload;
+    function ReadFrame(const ABuffer: TBLArrayView<Byte>): IBLImage; overload;
+    function ReadFrame(const ABuffer: Pointer; const ASize: Integer): IBLImage; overload;
+
+    { Tests whether the image decoder is a built-in nil instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Last decoding result. }
+    property LastResult: TBLResultCode read GetLastResult;
+
+    { Current frame index (to be decoded). }
+    property FrameIndex: Integer read GetFrameIndex;
+
+    { Position in source buffer. }
+    property BufferIndex: NativeInt read GetBufferIndex;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLImageDecoderCore read GetHandle;
+  end;
+
+  { Implements IBLImageDecoder }
+  TBLImageDecoder = class(TInterfacedObject, IBLImageDecoder)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLImageDecoderCore;
+  protected
+    { IBLImageDecoder }
+    function GetIsNone: Boolean;
+    function GetLastResult: TBLResultCode;
+    function GetFrameIndex: Integer;
+    function GetBufferIndex: NativeInt;
+    function GetHandle: PBLImageDecoderCore;
+
+    procedure Reset;
+    function Equals(const AOther: IBLImageDecoder): Boolean; reintroduce; overload;
+
+    procedure Restart;
+
+    procedure ReadInfo(const ABuffer: TBytes; out AInfo: TBLImageInfo); overload;
+    procedure ReadInfo(const ABuffer: TBLArrayView<Byte>; out AInfo: TBLImageInfo); overload;
+    procedure ReadInfo(const ABuffer: Pointer; const ASize: Integer; out AInfo: TBLImageInfo); overload;
+
+    function ReadFrame(const ABuffer: TBytes): IBLImage; overload;
+    function ReadFrame(const ABuffer: TBLArrayView<Byte>): IBLImage; overload;
+    function ReadFrame(const ABuffer: Pointer; const ASize: Integer): IBLImage; overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+
+{ ============================================================================
+   [BLImageEncoder]
+  ============================================================================ }
+
+  { Image encoder }
+  IBLImageEncoder = interface
+  ['{D754FC7A-AC83-4543-8200-AE896920FFB0}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetLastResult: TBLResultCode;
+    function GetFrameIndex: Integer;
+    function GetBufferIndex: NativeInt;
+    function GetHandle: PBLImageEncoderCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    procedure Reset;
+    function Equals(const AOther: IBLImageEncoder): Boolean;
+
+    procedure Restart;
+
+    { Encodes the given AImage and returns the encoded data. }
+    function WriteFrame(const AImage: IBLImage): TBytes;
+
+    { Tests whether the image encoder is a built-in nil instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Last encoding result. }
+    property LastResult: TBLResultCode read GetLastResult;
+
+    { Current frame index (yet to be written). }
+    property FrameIndex: Integer read GetFrameIndex;
+
+    { Position in destination buffer. }
+    property BufferIndex: NativeInt read GetBufferIndex;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLImageEncoderCore read GetHandle;
+  end;
+
+  { Implements IBLImageEncoder }
+  TBLImageEncoder = class(TInterfacedObject, IBLImageEncoder)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLImageEncoderCore;
+  protected
+    { IBLImageEncoder }
+    function GetIsNone: Boolean;
+    function GetLastResult: TBLResultCode;
+    function GetFrameIndex: Integer;
+    function GetBufferIndex: NativeInt;
+    function GetHandle: PBLImageEncoderCore;
+
+    procedure Reset;
+    function Equals(const AOther: IBLImageEncoder): Boolean; reintroduce; overload;
+
+    procedure Restart;
+
+    function WriteFrame(const AImage: IBLImage): TBytes;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+
+{ ============================================================================
+   [BLImageCodec]
+  ============================================================================ }
+
+  { Image codec.
+    Provides a unified interface for inspecting image data and creating image
+    decoders & encoders. }
+  IBLImageCodec = interface
+  ['{5F2E0C15-3CF5-4454-ADA4-CEE5D4A3B542}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetName: String;
+    function GetVendor: String;
+    function GetMimeType: String;
+    function GetExtensions: String;
+    function GetFeatures: TBLImageCodecFeatures;
+    function GetHandle: PBLImageCodecCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    procedure Reset;
+    function Equals(const AOther: IBLImageCodec): Boolean;
+
+    { Tests whether the image codec has a given feature. }
+    function HasFeature(const AFeature: TBLImageCodecFeature): Boolean;
+
+    function FindByName(const AName: String): Boolean; overload;
+    function FindByName(const AName: String; const ACodecs: TArray<IBLImageCodec>): Boolean; overload;
+
+    function FindByExtension(const AExt: String): Boolean; overload;
+    function FindByExtension(const AExt: String; const ACodecs: TArray<IBLImageCodec>): Boolean; overload;
+
+    function FindByData(const AData: Pointer; const ASize: Integer): Boolean; overload;
+    function FindByData(const AData: Pointer; const ASize: Integer;
+      const ACodecs: TArray<IBLImageCodec>): Boolean; overload;
+
+    function FindByData(const AData: TBytes): Boolean; overload;
+    function FindByData(const AData: TBytes;
+      const ACodecs: TArray<IBLImageCodec>): Boolean; overload;
+
+    { Returns a score }
+    function InspectData(const ABuffer: TBytes): Cardinal; overload;
+    function InspectData(const ABuffer: TBLArrayView<Byte>): Cardinal; overload;
+    function InspectData(const ABuffer: Pointer; const ASize: Integer): Cardinal; overload;
+
+    { Tests whether the image codec is a built-in nil instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Image codec name (i.e, "PNG", "JPEG", etc...). }
+    property Name: String read GetName;
+
+    { The image codec vendor (i.e. "Blend2D" for all built-in codecs). }
+    property Vendor: String read GetVendor;
+
+    { Mime-type associated with the image codec's format. }
+    property MimeType: String read GetMimeType;
+
+    { A list of file extensions used to store image of this codec, separated by
+      '|' character. }
+    property Extensions: String read GetExtensions;
+
+    { Image codec features }
+    property Features: TBLImageCodecFeatures read GetFeatures;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLImageCodecCore read GetHandle;
+  end;
+
+type
+  { Implements IBLImageCodec }
+  TBLImageCodec = class(TInterfacedObject, IBLImageCodec)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLImageCodecCore;
+    FIsReference: Boolean;
+  private
+    class function GetBuiltInCodecs: TArray<IBLImageCodec>; static;
+  protected
+    { IBLImageCodec }
+    function GetIsNone: Boolean;
+    function GetName: String;
+    function GetVendor: String;
+    function GetMimeType: String;
+    function GetExtensions: String;
+    function GetFeatures: TBLImageCodecFeatures;
+    function GetHandle: PBLImageCodecCore;
+
+    procedure Reset;
+    function Equals(const AOther: IBLImageCodec): Boolean; reintroduce; overload;
+    function HasFeature(const AFeature: TBLImageCodecFeature): Boolean;
+
+    function FindByName(const AName: String): Boolean; overload;
+    function FindByName(const AName: String; const ACodecs: TArray<IBLImageCodec>): Boolean; overload;
+
+    function FindByExtension(const AExt: String): Boolean; overload;
+    function FindByExtension(const AExt: String; const ACodecs: TArray<IBLImageCodec>): Boolean; overload;
+
+    function FindByData(const AData: Pointer; const ASize: Integer): Boolean; overload;
+    function FindByData(const AData: Pointer; const ASize: Integer;
+      const ACodecs: TArray<IBLImageCodec>): Boolean; overload;
+
+    function FindByData(const AData: TBytes): Boolean; overload;
+    function FindByData(const AData: TBytes;
+      const ACodecs: TArray<IBLImageCodec>): Boolean; overload;
+
+    function InspectData(const ABuffer: TBytes): Cardinal; overload;
+    function InspectData(const ABuffer: TBLArrayView<Byte>): Cardinal; overload;
+    function InspectData(const ABuffer: Pointer; const ASize: Integer): Cardinal; overload;
+  protected
+    constructor Create(const AHandle: BLImageCodecCore; const AIsReference: Boolean); overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create; overload;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+    class procedure AddToBuiltIn(const ACodec: IBLImageCodec); static;
+    class procedure RemoveFromBuiltIn(const ACodec: IBLImageCodec); static;
+
+    class property BuiltInCodecs: TArray<IBLImageCodec> read GetBuiltInCodecs;
+  end;
+
+{$ENDREGION 'Image Codec'}
+
+{$REGION 'Pattern'}
+
+{ ============================================================================
+   [BLPattern]
+  ============================================================================ }
+
+type
+  { Pattern }
+  IBLPattern = interface
+  ['{BE559BED-3495-49D7-AB00-7BF092E1F53B}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetImage: IBLImage;
+    procedure SetImage(const AValue: IBLImage); overload;
+    function GetArea: TBLRectI;
+    procedure SetArea(const AValue: TBLRectI);
+    function GetExtendMode: TBLExtendMode;
+    procedure SetExtendMode(const AValue: TBLExtendMode);
+    function GetHasMatrix: Boolean;
+    function GetMatrixType: TBLMatrix2DType;
+    function GetMatrix: TBLMatrix2D;
+    procedure SetMatrix(const AValue: TBLMatrix2D);
+    function GetHandle: PBLPatternCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    procedure Initialize(const AImage: IBLImage;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.&Repeat); overload;
+    procedure Initialize(const AImage: IBLImage; const AExtendMode: TBLExtendMode;
+      const AMatrix: TBLMatrix2D); overload;
+    procedure Initialize(const AImage: IBLImage; const AArea: TBLRectI;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.&Repeat); overload;
+    procedure Initialize(const AImage: IBLImage; const AArea: TBLRectI;
+      const AExtendMode: TBLExtendMode; const AMatrix: TBLMatrix2D); overload;
+
+    procedure Reset;
+    function Equals(const AOther: IBLPattern): Boolean;
+
+    procedure SetImage(const AValue: IBLImage; const AArea: TBLRectI); overload;
+    procedure ResetImage;
+    procedure ResetArea;
+    procedure ResetExtendMode;
+    procedure ResetMatrix;
+
+    procedure Translate(const AX, AY: Double); overload;
+    procedure Translate(const AP: TBLPoint); overload;
+    procedure Translate(const AP: TBLPointI); overload;
+    procedure Scale(const AXY: Double); overload;
+    procedure Scale(const AX, AY: Double); overload;
+    procedure Scale(const AP: TBLPoint); overload;
+    procedure Scale(const AP: TBLPointI); overload;
+    procedure Skew(const AX, AY: Double); overload;
+    procedure Skew(const AP: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double); overload;
+    procedure Rotate(const AAngle, AX, AY: Double); overload;
+    procedure Rotate(const AAngle: Double; const AP: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double; const AP: TBLPointI); overload;
+    procedure Transform(const AMatrix: TBLMatrix2D);
+
+    procedure PostTranslate(const AX, AY: Double); overload;
+    procedure PostTranslate(const AP: TBLPoint); overload;
+    procedure PostTranslate(const AP: TBLPointI); overload;
+    procedure PostScale(const AXY: Double); overload;
+    procedure PostScale(const AX, AY: Double); overload;
+    procedure PostScale(const AP: TBLPoint); overload;
+    procedure PostScale(const AP: TBLPointI); overload;
+    procedure PostSkew(const AX, AY: Double); overload;
+    procedure PostSkew(const AP: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double); overload;
+    procedure PostRotate(const AAngle, AX, AY: Double); overload;
+    procedure PostRotate(const AAngle: Double; const AP: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double; const AP: TBLPointI); overload;
+    procedure PostTransform(const AMatrix: TBLMatrix2D);
+
+    { Whether the pattern is a built-in null instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    property Image: IBLImage read GetImage write SetImage;
+    property Area: TBLRectI read GetArea write SetArea;
+    property ExtendMode: TBLExtendMode read GetExtendMode write SetExtendMode;
+
+    property HasMatrix: Boolean read GetHasMatrix;
+    property MatrixType: TBLMatrix2DType read GetMatrixType;
+    property Matrix: TBLMatrix2D read GetMatrix write SetMatrix;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLPatternCore read GetHandle;
+  end;
+
+type
+  { Implements IBLPattern }
+  TBLPattern = class(TInterfacedObject, IBLPattern)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLPatternCore;
+    FImage: IBLImage;
+    FIsReference: Boolean;
+  protected
+    { IBLPattern }
+    function GetIsNone: Boolean;
+    function GetImage: IBLImage;
+    procedure SetImage(const AValue: IBLImage); overload;
+    function GetArea: TBLRectI;
+    procedure SetArea(const AValue: TBLRectI);
+    function GetExtendMode: TBLExtendMode;
+    procedure SetExtendMode(const AValue: TBLExtendMode);
+    function GetHasMatrix: Boolean;
+    function GetMatrixType: TBLMatrix2DType;
+    function GetMatrix: TBLMatrix2D;
+    procedure SetMatrix(const AValue: TBLMatrix2D);
+    function GetHandle: PBLPatternCore;
+
+    procedure Initialize(const AImage: IBLImage;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.&Repeat); overload;
+    procedure Initialize(const AImage: IBLImage; const AExtendMode: TBLExtendMode;
+      const AMatrix: TBLMatrix2D); overload;
+    procedure Initialize(const AImage: IBLImage; const AArea: TBLRectI;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.&Repeat); overload;
+    procedure Initialize(const AImage: IBLImage; const AArea: TBLRectI;
+      const AExtendMode: TBLExtendMode; const AMatrix: TBLMatrix2D); overload;
+
+    procedure Reset;
+    function Equals(const AOther: IBLPattern): Boolean; reintroduce; overload;
+
+    procedure SetImage(const AValue: IBLImage; const AArea: TBLRectI); overload;
+    procedure ResetImage;
+    procedure ResetArea;
+    procedure ResetExtendMode;
+    procedure ResetMatrix;
+
+    procedure Translate(const AX, AY: Double); overload;
+    procedure Translate(const AP: TBLPoint); overload;
+    procedure Translate(const AP: TBLPointI); overload;
+    procedure Scale(const AXY: Double); overload;
+    procedure Scale(const AX, AY: Double); overload;
+    procedure Scale(const AP: TBLPoint); overload;
+    procedure Scale(const AP: TBLPointI); overload;
+    procedure Skew(const AX, AY: Double); overload;
+    procedure Skew(const AP: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double); overload;
+    procedure Rotate(const AAngle, AX, AY: Double); overload;
+    procedure Rotate(const AAngle: Double; const AP: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double; const AP: TBLPointI); overload;
+    procedure Transform(const AMatrix: TBLMatrix2D);
+
+    procedure PostTranslate(const AX, AY: Double); overload;
+    procedure PostTranslate(const AP: TBLPoint); overload;
+    procedure PostTranslate(const AP: TBLPointI); overload;
+    procedure PostScale(const AXY: Double); overload;
+    procedure PostScale(const AX, AY: Double); overload;
+    procedure PostScale(const AP: TBLPoint); overload;
+    procedure PostScale(const AP: TBLPointI); overload;
+    procedure PostSkew(const AX, AY: Double); overload;
+    procedure PostSkew(const AP: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double); overload;
+    procedure PostRotate(const AAngle, AX, AY: Double); overload;
+    procedure PostRotate(const AAngle: Double; const AP: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double; const AP: TBLPointI); overload;
+    procedure PostTransform(const AMatrix: TBLMatrix2D);
+  private
+    constructor Create(const AHandle: BLPatternCore;
+      const AIsReference: Boolean); overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create; overload;
+    constructor Create(const AImage: IBLImage;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.&Repeat); overload;
+    constructor Create(const AImage: IBLImage; const AExtendMode: TBLExtendMode;
+      const AMatrix: TBLMatrix2D); overload;
+    constructor Create(const AImage: IBLImage; const AArea: TBLRectI;
+      const AExtendMode: TBLExtendMode = TBLExtendMode.&Repeat); overload;
+    constructor Create(const AImage: IBLImage; const AArea: TBLRectI;
+      const AExtendMode: TBLExtendMode; const AMatrix: TBLMatrix2D); overload;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+
+{$ENDREGION 'Pattern'}
+
+{$REGION 'Font Defs'}
+
+{ ============================================================================
+   [Enums]
+  ============================================================================ }
+
+type
+  { Placement of glyphs stored in a TBLGlyphRun. }
+  TBLGlyphPlacementType = (
+    { No placement (custom handling by TBLPathSinkEvent). }
+    None          = BL_GLYPH_PLACEMENT_TYPE_NONE,
+
+    { Each glyph has a TBLGlyphPlacement (advance + offset). }
+    AdvanceOffset = BL_GLYPH_PLACEMENT_TYPE_ADVANCE_OFFSET,
+
+    { Each glyph has a TBLPoint offset in design-space units. }
+    DesignUnits   = BL_GLYPH_PLACEMENT_TYPE_DESIGN_UNITS,
+
+    { Each glyph has a TBLPoint offset in user-space units. }
+    UserUnits     = BL_GLYPH_PLACEMENT_TYPE_USER_UNITS,
+
+    { Each glyph has a TBLPoint offset in absolute units. }
+    AbsoluteUnits = BL_GLYPH_PLACEMENT_TYPE_ABSOLUTE_UNITS);
+
+type
+  TBLGlyphRunFlag = (
+    _Dummy          = 0,
+
+    { Glyph-run contains USC-4 string and not glyphs (glyph-buffer only). }
+    UCS4Content     = 28,
+
+    { Glyph-run was created from text that was not a valid unicode. }
+    InvalidText     = 29,
+
+    { Not the whole text was mapped to glyphs (contains undefined glyphs). }
+    UndefinedGlyphs = 30,
+
+    { Encountered invalid font-data during text / glyph processing. }
+    InvalidFontData = 31);
+
+  TBLGlyphRunFlags = set of TBLGlyphRunFlag;
+
+type
+  { Font-data flags. }
+  TBLFontDataFlag = (
+    { Font data references a font-collection. }
+    Collection = 0);
+  TBLFontDataFlags = set of TBLFontDataFlag;
+
+type
+  { Type of a font or font-face. }
+  TBLFontFaceType = (
+    None     = BL_FONT_FACE_TYPE_NONE,
+
+    { TrueType/OpenType font type. }
+    OpenType = BL_FONT_FACE_TYPE_OPENTYPE);
+
+type
+  TBLFontFaceFlag = (
+    { Font uses typographic family and subfamily names. }
+    TypographicNames   = 0,
+
+    { Font uses typographic metrics. }
+    TypographicMetrics = 1,
+
+    { Character to glyph mapping is available. }
+    CharToGlyphMapping = 2,
+
+    { Horizontal glyph metrics (advances, side bearings) is available. }
+    HorizontalMetrics  = 4,
+
+    { Vertical glyph metrics (advances, side bearings) is available. }
+    VerticalMetrics    = 5,
+
+    { Legacy horizontal kerning feature ('kern' table with horizontal kerning data). }
+    HorizontalKerning  = 6,
+
+    { Legacy vertical kerning feature ('kern' table with vertical kerning data). }
+    VerticalKerning    = 7,
+
+    { OpenType features (GDEF, GPOS, GSUB) are available. }
+    OpenTypeFeatures   = 8,
+
+    { Panose classification is available. }
+    PanoseData         = 9,
+
+    { Unicode coverage information is available. }
+    UnicodeCoverage    = 10,
+
+    { Baseline for font at `y` equals 0. }
+    BaselineYEquals0   = 12,
+
+    { Left sidebearing point at `x == 0` (TT only). }
+    LSBPointXEquals0   = 13,
+
+    { Unicode variation sequences feature is available. }
+    VariationSequences = 28,
+
+    { OpenType Font Variations feature is available. }
+    OpenTypeVariations = 29,
+
+    { This is a symbol font. }
+    SymbolFont         = 30,
+
+    { This is a last resort font. }
+    LastResortFont     = 31);
+  TBLFontFaceFlags = set of TBLFontFaceFlag;
+
+type
+  TBLFontFaceDiagFlag = (
+    { Wrong data in 'name' table. }
+    WrongNameData   = 0,
+
+    { Fixed data read from 'name' table and possibly fixed font family/subfamily
+      name. }
+    FixedNameData   = 1,
+
+    { Wrong data in 'kern' table [kerning disabled]. }
+    WrongKernData   = 2,
+
+    { Fixed data read from 'kern' table so it can be used. }
+    FixedKernData   = 3,
+
+    { Wrong data in 'cmap' table. }
+    WrongCMAPData   = 4,
+
+    { Wrong format in 'cmap' (sub)table. }
+    WrongCMAPFormat = 5,
+
+    { Wrong data in 'GDEF' table. }
+    WrongGDEFData   = 8,
+
+    { Wrong data in 'GPOS' table. }
+    WrongGPOSData   = 10,
+
+    { Wrong data in 'GSUB' table. }
+    WrongGSUBData   = 12);
+  TBLFontFaceDiagFlags = set of TBLFontFaceDiagFlag;
+
+type
+  { Format of an outline stored in a font. }
+  TBLFontOutlineType = (
+    { None. }
+    None     = BL_FONT_OUTLINE_TYPE_NONE,
+
+    { TrueType outlines. }
+    TrueType = BL_FONT_OUTLINE_TYPE_TRUETYPE,
+
+    { OpenType (CFF) outlines. }
+    CFF      = BL_FONT_OUTLINE_TYPE_CFF,
+
+    { OpenType (CFF2) outlines (font variations support). }
+    CFF2     = BL_FONT_OUTLINE_TYPE_CFF2);
+
+type
+  { Font stretch. }
+  TBLFontStretch = (
+    { Ultra condensed stretch. }
+    UltraCondensed = BL_FONT_STRETCH_ULTRA_CONDENSED,
+
+    { Extra condensed stretch. }
+    ExtraCondensed = BL_FONT_STRETCH_EXTRA_CONDENSED,
+
+    { Condensed stretch. }
+    Condensed      = BL_FONT_STRETCH_CONDENSED,
+
+    { Semi condensed stretch. }
+    SemiCondensed  = BL_FONT_STRETCH_SEMI_CONDENSED,
+
+    { Normal stretch. }
+    Normal         = BL_FONT_STRETCH_NORMAL,
+
+    { Semi expanded stretch. }
+    SemiExpanded   = BL_FONT_STRETCH_SEMI_EXPANDED,
+
+    { Expanded stretch. }
+    Expanded       = BL_FONT_STRETCH_EXPANDED,
+
+    { Extra expanded stretch. }
+    ExtraExpanded  = BL_FONT_STRETCH_EXTRA_EXPANDED,
+
+    { Ultra expanded stretch. }
+    UltraExpanded  = BL_FONT_STRETCH_ULTRA_EXPANDED);
+
+type
+  { Font style. }
+  TBLFontStyle = (
+    { Normal style. }
+    Normal = BL_FONT_STYLE_NORMAL,
+
+    { Oblique. }
+    Oblique = BL_FONT_STYLE_OBLIQUE,
+
+    { Italic. }
+    Italic  = BL_FONT_STYLE_ITALIC);
+
+type
+  { Font weight. }
+  TBLFontWeight = (
+    { Thin weight (100). }
+    Thin = BL_FONT_WEIGHT_THIN,
+
+    { Extra light weight (200). }
+    ExtraLight = BL_FONT_WEIGHT_EXTRA_LIGHT,
+
+    { Light weight (300). }
+    Light      = BL_FONT_WEIGHT_LIGHT,
+
+    { Semi light weight (350). }
+    SemiLight  = BL_FONT_WEIGHT_SEMI_LIGHT,
+
+    { Normal weight (400). }
+    Normal     = BL_FONT_WEIGHT_NORMAL,
+
+    { Medium weight (500). }
+    Medium     = BL_FONT_WEIGHT_MEDIUM,
+
+    { Semi bold weight (600). }
+    SemiBold   = BL_FONT_WEIGHT_SEMI_BOLD,
+
+    { Bold weight (700). }
+    Bold       = BL_FONT_WEIGHT_BOLD,
+
+    { Extra bold weight (800). }
+    ExtraBold  = BL_FONT_WEIGHT_EXTRA_BOLD,
+
+    { Black weight (900). }
+    Black      = BL_FONT_WEIGHT_BLACK,
+
+    { Extra black weight (950). }
+    ExtraBlack = BL_FONT_WEIGHT_EXTRA_BLACK);
+
+type
+  { Font string identifiers used by OpenType 'name' table. }
+  TBLFontStringId = (
+    { Copyright notice. }
+    CopyrightNotice           = BL_FONT_STRING_COPYRIGHT_NOTICE,
+
+    { Font family name. }
+    FamilyName                = BL_FONT_STRING_FAMILY_NAME,
+
+    { Font subfamily name. }
+    SubfamilyName             = BL_FONT_STRING_SUBFAMILY_NAME,
+
+    { Unique font identifier. }
+    UniqueIdentifier          = BL_FONT_STRING_UNIQUE_IDENTIFIER,
+
+    { Full font name that reflects all family and relevant subfamily descriptors. }
+    FullName                  = BL_FONT_STRING_FULL_NAME,
+
+    { Version string. Should begin with the synta `Version <number>.<number>`. }
+    VersionString             = BL_FONT_STRING_VERSION_STRING,
+
+    { PostScript name for the font. }
+    PostScriptName            = BL_FONT_STRING_POST_SCRIPT_NAME,
+
+    { Trademark notice/information for this font. }
+    Trademark                 = BL_FONT_STRING_TRADEMARK,
+
+    { Manufacturer name. }
+    ManufacturerName          = BL_FONT_STRING_MANUFACTURER_NAME,
+
+    { Name of the designer of the typeface. }
+    DesignerName              = BL_FONT_STRING_DESIGNER_NAME,
+
+    { Description of the typeface. }
+    Description               = BL_FONT_STRING_DESCRIPTION,
+
+    { URL of font vendor. }
+    VendorURL                 = BL_FONT_STRING_VENDOR_URL,
+
+    { URL of typeface designer. }
+    DesignerURL               = BL_FONT_STRING_DESIGNER_URL,
+
+    { Description of how the font may be legally used. }
+    LicenseDescription        = BL_FONT_STRING_LICENSE_DESCRIPTION,
+
+    { URL where additional licensing information can be found. }
+    LicenseInfoURL            = BL_FONT_STRING_LICENSE_INFO_URL,
+
+    { Reserved. }
+    Reserved                  = BL_FONT_STRING_RESERVED,
+
+    { Typographic family name. }
+    TypographicFamilyName     = BL_FONT_STRING_TYPOGRAPHIC_FAMILY_NAME,
+
+    { Typographic subfamily name. }
+    TypographicSubfamilyName  = BL_FONT_STRING_TYPOGRAPHIC_SUBFAMILY_NAME,
+
+    { Compatible full name (MAC only). }
+    CompatibleFullName        = BL_FONT_STRING_COMPATIBLE_FULL_NAME,
+
+    { Sample text - font name or any other text from the designer. }
+    SampleText                = BL_FONT_STRING_SAMPLE_TEXT,
+
+    { PostScript CID findfont name. }
+    PostScriptCIDName         = BL_FONT_STRING_POST_SCRIPT_CID_NAME,
+
+    { WWS family name. }
+    WWSFamilyName             = BL_FONT_STRING_WWS_FAMILY_NAME,
+
+    { WWS subfamily name. }
+    WWSSubfamilyName          = BL_FONT_STRING_WWS_SUBFAMILY_NAME,
+
+    { Light background palette. }
+    LightBackgroundPalette    = BL_FONT_STRING_LIGHT_BACKGROUND_PALETTE,
+
+    { Dark background palette. }
+    DarkBackgroundPalette     = BL_FONT_STRING_DARK_BACKGROUND_PALETTE,
+
+    { Variations PostScript name prefix. }
+    VariationsPostSciptPrefix = BL_FONT_STRING_VARIATIONS_POST_SCRIPT_PREFIX);
+
+type
+  { Bit positions in TBLFontUnicodeCoverage record.
+    Each bit represents a range (or multiple ranges) of unicode characters. }
+  TBLFontUnicodeCoverageIndex = (
+    BasicLatin                          = BL_FONT_UC_INDEX_BASIC_LATIN,                              // [000000-00007F] Basic Latin.
+    Latin1Supplement                    = BL_FONT_UC_INDEX_LATIN1_SUPPLEMENT,                        // [000080-0000FF] Latin-1 Supplement.
+    LatinExtendedA                      = BL_FONT_UC_INDEX_LATIN_EXTENDED_A,                         // [000100-00017F] Latin Extended-A.
+    LatinExtendedB                      = BL_FONT_UC_INDEX_LATIN_EXTENDED_B,                         // [000180-00024F] Latin Extended-B.
+    IPAExtensions                       = BL_FONT_UC_INDEX_IPA_EXTENSIONS,                           // [000250-0002AF] IPA Extensions.
+                                                                                                     // [001D00-001D7F] Phonetic Extensions.
+                                                                                                     // [001D80-001DBF] Phonetic Extensions Supplement.
+    SpacingModifierLetters              = BL_FONT_UC_INDEX_SPACING_MODIFIER_LETTERS,                 // [0002B0-0002FF] Spacing Modifier Letters.
+                                                                                                     // [00A700-00A71F] Modifier Tone Letters.
+                                                                                                     // [001DC0-001DFF] Combining Diacritical Marks Supplement.
+    CombiningDiacriticalMarks           = BL_FONT_UC_INDEX_COMBINING_DIACRITICAL_MARKS,              // [000300-00036F] Combining Diacritical Marks.
+    GreekAndCoptic                      = BL_FONT_UC_INDEX_GREEK_AND_COPTIC,                         // [000370-0003FF] Greek and Coptic.
+    Coptic                              = BL_FONT_UC_INDEX_COPTIC,                                   // [002C80-002CFF] Coptic.
+    Cyrillic                            = BL_FONT_UC_INDEX_CYRILLIC,                                 // [000400-0004FF] Cyrillic.
+                                                                                                     // [000500-00052F] Cyrillic Supplement.
+                                                                                                     // [002DE0-002DFF] Cyrillic Extended-A.
+                                                                                                     // [00A640-00A69F] Cyrillic Extended-B.
+    Armenian                            = BL_FONT_UC_INDEX_ARMENIAN,                                 // [000530-00058F] Armenian.
+    Hebrew                              = BL_FONT_UC_INDEX_HEBREW,                                   // [000590-0005FF] Hebrew.
+    Vai                                 = BL_FONT_UC_INDEX_VAI,                                      // [00A500-00A63F] Vai.
+    Arabic                              = BL_FONT_UC_INDEX_ARABIC,                                   // [000600-0006FF] Arabic.
+                                                                                                     // [000750-00077F] Arabic Supplement.
+    NKo                                 = BL_FONT_UC_INDEX_NKO,                                      // [0007C0-0007FF] NKo.
+    Devanagari                          = BL_FONT_UC_INDEX_DEVANAGARI,                               // [000900-00097F] Devanagari.
+    Bengali                             = BL_FONT_UC_INDEX_BENGALI,                                  // [000980-0009FF] Bengali.
+    Gurmukhi                            = BL_FONT_UC_INDEX_GURMUKHI,                                 // [000A00-000A7F] Gurmukhi.
+    Gujarati                            = BL_FONT_UC_INDEX_GUJARATI,                                 // [000A80-000AFF] Gujarati.
+    Oriya                               = BL_FONT_UC_INDEX_ORIYA,                                    // [000B00-000B7F] Oriya.
+    Tamil                               = BL_FONT_UC_INDEX_TAMIL,                                    // [000B80-000BFF] Tamil.
+    Telugu                              = BL_FONT_UC_INDEX_TELUGU,                                   // [000C00-000C7F] Telugu.
+    Kannada                             = BL_FONT_UC_INDEX_KANNADA,                                  // [000C80-000CFF] Kannada.
+    Malayalam                           = BL_FONT_UC_INDEX_MALAYALAM,                                // [000D00-000D7F] Malayalam.
+    Thai                                = BL_FONT_UC_INDEX_THAI,                                     // [000E00-000E7F] Thai.
+    Lao                                 = BL_FONT_UC_INDEX_LAO,                                      // [000E80-000EFF] Lao.
+    Georgian                            = BL_FONT_UC_INDEX_GEORGIAN,                                 // [0010A0-0010FF] Georgian.
+                                                                                                     // [002D00-002D2F] Georgian Supplement.
+    Balinese                            = BL_FONT_UC_INDEX_BALINESE,                                 // [001B00-001B7F] Balinese.
+    HangulJamo                          = BL_FONT_UC_INDEX_HANGUL_JAMO,                              // [001100-0011FF] Hangul Jamo.
+    LatinExtendedAdditional             = BL_FONT_UC_INDEX_LATIN_EXTENDED_ADDITIONAL,                // [001E00-001EFF] Latin Extended Additional.
+                                                                                                     // [002C60-002C7F] Latin Extended-C.
+                                                                                                     // [00A720-00A7FF] Latin Extended-D.
+    GreekExtended                       = BL_FONT_UC_INDEX_GREEK_EXTENDED,                           // [001F00-001FFF] Greek Extended.
+    GeneralPunctuation                  = BL_FONT_UC_INDEX_GENERAL_PUNCTUATION,                      // [002000-00206F] General Punctuation.
+                                                                                                     // [002E00-002E7F] Supplemental Punctuation.
+    SuperscriptsAndSubscripts           = BL_FONT_UC_INDEX_SUPERSCRIPTS_AND_SUBSCRIPTS,              // [002070-00209F] Superscripts And Subscripts.
+    CurrencySymbols                     = BL_FONT_UC_INDEX_CURRENCY_SYMBOLS,                         // [0020A0-0020CF] Currency Symbols.
+    CombiningDiacriticalMarksForSymbols = BL_FONT_UC_INDEX_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS,  // [0020D0-0020FF] Combining Diacritical Marks For Symbols.
+    LetterlikeSymbols                   = BL_FONT_UC_INDEX_LETTERLIKE_SYMBOLS,                       // [002100-00214F] Letterlike Symbols.
+    NumberForms                         = BL_FONT_UC_INDEX_NUMBER_FORMS,                             // [002150-00218F] Number Forms.
+    Arrows                              = BL_FONT_UC_INDEX_ARROWS,                                   // [002190-0021FF] Arrows.
+                                                                                                     // [0027F0-0027FF] Supplemental Arrows-A.
+                                                                                                     // [002900-00297F] Supplemental Arrows-B.
+                                                                                                     // [002B00-002BFF] Miscellaneous Symbols and Arrows.
+    MathematicalOperators               = BL_FONT_UC_INDEX_MATHEMATICAL_OPERATORS,                   // [002200-0022FF] Mathematical Operators.
+                                                                                                     // [002A00-002AFF] Supplemental Mathematical Operators.
+                                                                                                     // [0027C0-0027EF] Miscellaneous Mathematical Symbols-A.
+                                                                                                     // [002980-0029FF] Miscellaneous Mathematical Symbols-B.
+    MiscellaneousTechnical              = BL_FONT_UC_INDEX_MISCELLANEOUS_TECHNICAL,                  // [002300-0023FF] Miscellaneous Technical.
+    ControlPictures                     = BL_FONT_UC_INDEX_CONTROL_PICTURES,                         // [002400-00243F] Control Pictures.
+    OpticalCharacterRecognition         = BL_FONT_UC_INDEX_OPTICAL_CHARACTER_RECOGNITION,            // [002440-00245F] Optical Character Recognition.
+    EnclosedAlphanumerics               = BL_FONT_UC_INDEX_ENCLOSED_ALPHANUMERICS,                   // [002460-0024FF] Enclosed Alphanumerics.
+    BoxDrawing                          = BL_FONT_UC_INDEX_BOX_DRAWING,                              // [002500-00257F] Box Drawing.
+    BlockElements                       = BL_FONT_UC_INDEX_BLOCK_ELEMENTS,                           // [002580-00259F] Block Elements.
+    GeometricShapes                     = BL_FONT_UC_INDEX_GEOMETRIC_SHAPES,                         // [0025A0-0025FF] Geometric Shapes.
+    MiscellaneousSymbols                = BL_FONT_UC_INDEX_MISCELLANEOUS_SYMBOLS,                    // [002600-0026FF] Miscellaneous Symbols.
+    Dingbats                            = BL_FONT_UC_INDEX_DINGBATS,                                 // [002700-0027BF] Dingbats.
+    CJKSymbolsAndPunctuation            = BL_FONT_UC_INDEX_CJK_SYMBOLS_AND_PUNCTUATION,              // [003000-00303F] CJK Symbols And Punctuation.
+    Hiragana                            = BL_FONT_UC_INDEX_HIRAGANA,                                 // [003040-00309F] Hiragana.
+    Katakana                            = BL_FONT_UC_INDEX_KATAKANA,                                 // [0030A0-0030FF] Katakana.
+                                                                                                     // [0031F0-0031FF] Katakana Phonetic Extensions.
+    Bopomofo                            = BL_FONT_UC_INDEX_BOPOMOFO,                                 // [003100-00312F] Bopomofo.
+                                                                                                     // [0031A0-0031BF] Bopomofo Extended.
+    HangulCompatibilityJamo             = BL_FONT_UC_INDEX_HANGUL_COMPATIBILITY_JAMO,                // [003130-00318F] Hangul Compatibility Jamo.
+    PhagsPa                             = BL_FONT_UC_INDEX_PHAGS_PA,                                 // [00A840-00A87F] Phags-pa.
+    EnclosedCJKLettersAndMonths         = BL_FONT_UC_INDEX_ENCLOSED_CJK_LETTERS_AND_MONTHS,          // [003200-0032FF] Enclosed CJK Letters And Months.
+    CJKCompatibility                    = BL_FONT_UC_INDEX_CJK_COMPATIBILITY,                        // [003300-0033FF] CJK Compatibility.
+    HangulSyllables                     = BL_FONT_UC_INDEX_HANGUL_SYLLABLES,                         // [00AC00-00D7AF] Hangul Syllables.
+    NonPlane                            = BL_FONT_UC_INDEX_NON_PLANE,                                // [00D800-00DFFF] Non-Plane 0 *.
+    Phoenician                          = BL_FONT_UC_INDEX_PHOENICIAN,                               // [010900-01091F] Phoenician.
+    CJKUnifiedIdeographs                = BL_FONT_UC_INDEX_CJK_UNIFIED_IDEOGRAPHS,                   // [004E00-009FFF] CJK Unified Ideographs.
+                                                                                                     // [002E80-002EFF] CJK Radicals Supplement.
+                                                                                                     // [002F00-002FDF] Kangxi Radicals.
+                                                                                                     // [002FF0-002FFF] Ideographic Description Characters.
+                                                                                                     // [003400-004DBF] CJK Unified Ideographs Extension A.
+                                                                                                     // [020000-02A6DF] CJK Unified Ideographs Extension B.
+                                                                                                     // [003190-00319F] Kanbun.
+    PrivateUsePlane0                    = BL_FONT_UC_INDEX_PRIVATE_USE_PLANE0,                       // [00E000-00F8FF] Private Use (Plane 0).
+    CJKStrokes                          = BL_FONT_UC_INDEX_CJK_STROKES,                              // [0031C0-0031EF] CJK Strokes.
+                                                                                                     // [00F900-00FAFF] CJK Compatibility Ideographs.
+                                                                                                     // [02F800-02FA1F] CJK Compatibility Ideographs Supplement.
+    AlphabeticPresentationForms         = BL_FONT_UC_INDEX_ALPHABETIC_PRESENTATION_FORMS,            // [00FB00-00FB4F] Alphabetic Presentation Forms.
+    ArabicPresentationsFormsA           = BL_FONT_UC_INDEX_ARABIC_PRESENTATION_FORMS_A,              // [00FB50-00FDFF] Arabic Presentation Forms-A.
+    CombiningHalfMarks                  = BL_FONT_UC_INDEX_COMBINING_HALF_MARKS,                     // [00FE20-00FE2F] Combining Half Marks.
+    VerticalForms                       = BL_FONT_UC_INDEX_VERTICAL_FORMS,                           // [00FE10-00FE1F] Vertical Forms.
+                                                                                                     // [00FE30-00FE4F] CJK Compatibility Forms.
+    SmallFormVariants                   = BL_FONT_UC_INDEX_SMALL_FORM_VARIANTS,                      // [00FE50-00FE6F] Small Form Variants.
+    ArabicPresentationFormsB            = BL_FONT_UC_INDEX_ARABIC_PRESENTATION_FORMS_B,              // [00FE70-00FEFF] Arabic Presentation Forms-B.
+    HalfwidthAndFullwidthForms          = BL_FONT_UC_INDEX_HALFWIDTH_AND_FULLWIDTH_FORMS,            // [00FF00-00FFEF] Halfwidth And Fullwidth Forms.
+    Specials                            = BL_FONT_UC_INDEX_SPECIALS,                                 // [00FFF0-00FFFF] Specials.
+    Tibetan                             = BL_FONT_UC_INDEX_TIBETAN,                                  // [000F00-000FFF] Tibetan.
+    Syriac                              = BL_FONT_UC_INDEX_SYRIAC,                                   // [000700-00074F] Syriac.
+    Thaana                              = BL_FONT_UC_INDEX_THAANA,                                   // [000780-0007BF] Thaana.
+    Sinhala                             = BL_FONT_UC_INDEX_SINHALA,                                  // [000D80-000DFF] Sinhala.
+    Myanmar                             = BL_FONT_UC_INDEX_MYANMAR,                                  // [001000-00109F] Myanmar.
+    Ethiopic                            = BL_FONT_UC_INDEX_ETHIOPIC,                                 // [001200-00137F] Ethiopic.
+                                                                                                     // [001380-00139F] Ethiopic Supplement.
+                                                                                                     // [002D80-002DDF] Ethiopic Extended.
+    Cherokee                            = BL_FONT_UC_INDEX_CHEROKEE,                                 // [0013A0-0013FF] Cherokee.
+    UnifiedCanadianAboriginalSyllabics  = BL_FONT_UC_INDEX_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS,    // [001400-00167F] Unified Canadian Aboriginal Syllabics.
+    Ogham                               = BL_FONT_UC_INDEX_OGHAM,                                    // [001680-00169F] Ogham.
+    Runic                               = BL_FONT_UC_INDEX_RUNIC,                                    // [0016A0-0016FF] Runic.
+    Khmer                               = BL_FONT_UC_INDEX_KHMER,                                    // [001780-0017FF] Khmer.
+                                                                                                     // [0019E0-0019FF] Khmer Symbols.
+    Mongolian                           = BL_FONT_UC_INDEX_MONGOLIAN,                                // [001800-0018AF] Mongolian.
+    BraillePatterns                     = BL_FONT_UC_INDEX_BRAILLE_PATTERNS,                         // [002800-0028FF] Braille Patterns.
+    YiSyllablesAndRadicals              = BL_FONT_UC_INDEX_YI_SYLLABLES_AND_RADICALS,                // [00A000-00A48F] Yi Syllables.
+                                                                                                     // [00A490-00A4CF] Yi Radicals.
+    TagalogHanunooBuhidTagbanwa         = BL_FONT_UC_INDEX_TAGALOG_HANUNOO_BUHID_TAGBANWA,           // [001700-00171F] Tagalog.
+                                                                                                     // [001720-00173F] Hanunoo.
+                                                                                                     // [001740-00175F] Buhid.
+                                                                                                     // [001760-00177F] Tagbanwa.
+    OldItalic                           = BL_FONT_UC_INDEX_OLD_ITALIC,                               // [010300-01032F] Old Italic.
+    Gothic                              = BL_FONT_UC_INDEX_GOTHIC,                                   // [010330-01034F] Gothic.
+    Deseret                             = BL_FONT_UC_INDEX_DESERET,                                  // [010400-01044F] Deseret.
+    MusicalSymbols                      = BL_FONT_UC_INDEX_MUSICAL_SYMBOLS,                          // [01D000-01D0FF] Byzantine Musical Symbols.
+                                                                                                     // [01D100-01D1FF] Musical Symbols.
+                                                                                                     // [01D200-01D24F] Ancient Greek Musical Notation.
+    MathematicalAlphanumericSymbols     = BL_FONT_UC_INDEX_MATHEMATICAL_ALPHANUMERIC_SYMBOLS,        // [01D400-01D7FF] Mathematical Alphanumeric Symbols.
+    PrivateUsePlane15And16              = BL_FONT_UC_INDEX_PRIVATE_USE_PLANE_15_16,                  // [0F0000-0FFFFD] Private Use (Plane 15).
+                                                                                                     // [100000-10FFFD] Private Use (Plane 16).
+    VariationSelectors                  = BL_FONT_UC_INDEX_VARIATION_SELECTORS,                      // [00FE00-00FE0F] Variation Selectors.
+                                                                                                     // [0E0100-0E01EF] Variation Selectors Supplement.
+    Tags                                = BL_FONT_UC_INDEX_TAGS,                                     // [0E0000-0E007F] Tags.
+    Limbu                               = BL_FONT_UC_INDEX_LIMBU,                                    // [001900-00194F] Limbu.
+    TaiLe                               = BL_FONT_UC_INDEX_TAI_LE,                                   // [001950-00197F] Tai Le.
+    NewTaiLue                           = BL_FONT_UC_INDEX_NEW_TAI_LUE,                              // [001980-0019DF] New Tai Lue.
+    Buginese                            = BL_FONT_UC_INDEX_BUGINESE,                                 // [001A00-001A1F] Buginese.
+    Glagolitic                          = BL_FONT_UC_INDEX_GLAGOLITIC,                               // [002C00-002C5F] Glagolitic.
+    Tifinagh                            = BL_FONT_UC_INDEX_TIFINAGH,                                 // [002D30-002D7F] Tifinagh.
+    YijingHexagramSymbols               = BL_FONT_UC_INDEX_YIJING_HEXAGRAM_SYMBOLS,                  // [004DC0-004DFF] Yijing Hexagram Symbols.
+    SylotiNagri                         = BL_FONT_UC_INDEX_SYLOTI_NAGRI,                             // [00A800-00A82F] Syloti Nagri.
+    LinearBSyllabaryAndIdeograms        = BL_FONT_UC_INDEX_LINEAR_B_SYLLABARY_AND_IDEOGRAMS,         // [010000-01007F] Linear B Syllabary.
+                                                                                                     // [010080-0100FF] Linear B Ideograms.
+                                                                                                     // [010100-01013F] Aegean Numbers.
+    AncientGreekNumbers                 = BL_FONT_UC_INDEX_ANCIENT_GREEK_NUMBERS,                    // [010140-01018F] Ancient Greek Numbers.
+    Ugaritic                            = BL_FONT_UC_INDEX_UGARITIC,                                 // [010380-01039F] Ugaritic.
+    OldPersian                          = BL_FONT_UC_INDEX_OLD_PERSIAN,                              // [0103A0-0103DF] Old Persian.
+    Shavian                             = BL_FONT_UC_INDEX_SHAVIAN,                                  // [010450-01047F] Shavian.
+    Osmanya                             = BL_FONT_UC_INDEX_OSMANYA,                                  // [010480-0104AF] Osmanya.
+    CypriotSyllabary                    = BL_FONT_UC_INDEX_CYPRIOT_SYLLABARY,                        // [010800-01083F] Cypriot Syllabary.
+    Kharoshthi                          = BL_FONT_UC_INDEX_KHAROSHTHI,                               // [010A00-010A5F] Kharoshthi.
+    TaiXuanJingSymbols                  = BL_FONT_UC_INDEX_TAI_XUAN_JING_SYMBOLS,                    // [01D300-01D35F] Tai Xuan Jing Symbols.
+    Cuneiform                           = BL_FONT_UC_INDEX_CUNEIFORM,                                // [012000-0123FF] Cuneiform.
+                                                                                                     // [012400-01247F] Cuneiform Numbers and Punctuation.
+    CountingRodNumerals                 = BL_FONT_UC_INDEX_COUNTING_ROD_NUMERALS,                    // [01D360-01D37F] Counting Rod Numerals.
+    Sundanese                           = BL_FONT_UC_INDEX_SUNDANESE,                                // [001B80-001BBF] Sundanese.
+    Lepcha                              = BL_FONT_UC_INDEX_LEPCHA,                                   // [001C00-001C4F] Lepcha.
+    OlChiki                             = BL_FONT_UC_INDEX_OL_CHIKI,                                 // [001C50-001C7F] Ol Chiki.
+    Saurashtra                          = BL_FONT_UC_INDEX_SAURASHTRA,                               // [00A880-00A8DF] Saurashtra.
+    KayahLi                             = BL_FONT_UC_INDEX_KAYAH_LI,                                 // [00A900-00A92F] Kayah Li.
+    Rejang                              = BL_FONT_UC_INDEX_REJANG,                                   // [00A930-00A95F] Rejang.
+    Cham                                = BL_FONT_UC_INDEX_CHAM,                                     // [00AA00-00AA5F] Cham.
+    AncientSymbols                      = BL_FONT_UC_INDEX_ANCIENT_SYMBOLS,                          // [010190-0101CF] Ancient Symbols.
+    PhaistosDisc                        = BL_FONT_UC_INDEX_PHAISTOS_DISC,                            // [0101D0-0101FF] Phaistos Disc.
+    CarianLycianLydian                  = BL_FONT_UC_INDEX_CARIAN_LYCIAN_LYDIAN,                     // [0102A0-0102DF] Carian.
+                                                                                                     // [010280-01029F] Lycian.
+                                                                                                     // [010920-01093F] Lydian.
+    DominoAndMahjongTiles               = BL_FONT_UC_INDEX_DOMINO_AND_MAHJONG_TILES,                 // [01F030-01F09F] Domino Tiles.
+                                                                                                     // [01F000-01F02F] Mahjong Tiles.
+    InternalUsage123                    = BL_FONT_UC_INDEX_INTERNAL_USAGE_123,                       // Reserved for internal usage (123).
+    InternalUsage124                    = BL_FONT_UC_INDEX_INTERNAL_USAGE_124,                       // Reserved for internal usage (124).
+    InternalUsage125                    = BL_FONT_UC_INDEX_INTERNAL_USAGE_125,                       // Reserved for internal usage (125).
+    InternalUsage126                    = BL_FONT_UC_INDEX_INTERNAL_USAGE_126,                       // Reserved for internal usage (126).
+    InternalUsage127                    = BL_FONT_UC_INDEX_INTERNAL_USAGE_127);                      // Reserved for internal usage (127).
+
+type
+  { Text direction. }
+  TBLTextDirection = (
+    { Left-to-right direction. }
+    LTR = BL_TEXT_DIRECTION_LTR,
+
+    { Right-to-left direction. }
+    RTL = BL_TEXT_DIRECTION_RTL);
+
+type
+  { Text orientation. }
+  TBLTextOrientation = (
+    { Horizontal orientation. }
+    Horizontal = BL_TEXT_ORIENTATION_HORIZONTAL,
+
+    { Vertical orientation. }
+    Vertical   = BL_TEXT_ORIENTATION_VERTICAL);
+
+{ ============================================================================
+   [BLGlyphInfo]
+  ============================================================================ }
+
+type
+  { Contains additional information associated with a glyph used by
+    IBLGlyphBuffer. }
+  TBLGlyphInfo = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLGlyphInfo;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    property Cluster: Cardinal read FHandle.cluster write FHandle.cluster;
+  end;
+  PBLGlyphInfo = ^TBLGlyphInfo;
+
+{ ============================================================================
+   [BLGlyphPlacement]
+  ============================================================================ }
+
+type
+  { Glyph placement.
+
+    Provides information about glyph offset (x/y) and advance (x/y). }
+  TBLGlyphPlacement = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLGlyphPlacement;
+    function GetPlacement: TBLPointI; inline;
+    procedure SetPlacement(const AValue: TBLPointI); inline;
+    function GetAdvance: TBLPointI; inline;
+    procedure SetAdvance(const AValue: TBLPointI); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    property Placement: TBLPointI read GetPlacement write SetPlacement;
+    property Advance: TBLPointI read GetAdvance write SetAdvance;
+  end;
+  PBLGlyphPlacement = ^TBLGlyphPlacement;
+
+{ ============================================================================
+   [BLGlyphMappingState]
+  ============================================================================ }
+
+type
+  { Character to glyph mapping state. }
+  TBLGlyphMappingState = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLGlyphMappingState;
+    function GetGlyphCount: Integer; inline;
+    procedure SetGlyphCount(const AValue: Integer); inline;
+    function GetUndefinedFirst: Integer; inline;
+    procedure SetUndefinedFirst(const AValue: Integer); inline;
+    function GetUndefinedCount: Integer; inline;
+    procedure SetUndefinedCount(const AValue: Integer); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    { Number of glyphs or glyph-items on output. }
+    property GlyphCount: Integer read GetGlyphCount write SetGlyphCount;
+
+    { Index of the first undefined glyph (-1 if none). }
+    property UndefinedFirst: Integer read GetUndefinedFirst write SetUndefinedFirst;
+
+    { Undefined glyph count (chars that have no mapping). }
+    property UndefinedCount: Integer read GetUndefinedCount write SetUndefinedCount;
+  end;
+  PBLGlyphMappingState = ^TBLGlyphMappingState;
+
+{ ============================================================================
+   [BLGlyphOutlineSinkInfo]
+  ============================================================================ }
+
+type
+  { Information passed to a TBLPathSinkEvent sink by IBLFont.GetGlyphOutlines. }
+  TBLGlyphOutlineSinkInfo = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLGlyphOutlineSinkInfo;
+    function GetGlyphIndex: Integer; inline;
+    procedure SetGlyphIndex(const AValue: Integer); inline;
+    function GetContourCount: Integer; inline;
+    procedure SetContourCount(const AValue: Integer); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    property GlyphIndex: Integer read GetGlyphIndex write SetGlyphIndex;
+    property ContourCount: Integer read GetContourCount write SetContourCount;
+  end;
+  PBLGlyphOutlineSinkInfo = ^TBLGlyphOutlineSinkInfo;
+
+{ ============================================================================
+   [BLGlyphRun]
+  ============================================================================ }
+
+type
+  { An entry enumerated by TBLGlyphRun.GetEnumerator }
+  TBLGlyphRunEntry<TPlacement: record> = record
+  public
+    { The glyph Id }
+    GlyphId: Cardinal;
+
+    { Glyph placement (type should match TBLGlyphRun.PlacementType) }
+    Placement: TPlacement;
+  end;
+
+type
+  { TBLGlyphRun describes a set of consecutive glyphs and their placements.
+
+    TBLGlyphRun should only be used to pass glyph IDs and their placements to
+    the rendering context. The purpose of TBLGlyphRun is to allow rendering
+    glyphs, which could be shaped by various shaping engines (Blend2D, Harfbuzz,
+    etc).
+
+    TBLGlyphRun allows to render glyphs that are either stored in TArray<UInt16>
+    or TArray<UInt32> or part of a bigger structure (for example hb_glyph_info_t
+    used by HarfBuzz). Glyph placements at the moment use Blend2D's
+    TBLGlyphPlacement or TBLPoint, but it's possible to extend the data type in
+    the future.
+
+    See TBLGlyphRunPlacement for placement modes provided by Blend2D. }
+  TBLGlyphRun = record
+  {$REGION 'Internal Declarations'}
+  private type
+    TEnumerator<T: record> = record
+    private type
+      P = ^T;
+    private
+      FGlyphData: PByte;
+      FPlacementData: PByte;
+      FGlyphAdvance: Integer;
+      FPlacementAdvance: Integer;
+      FHigh: Integer;
+      FIndex: Integer;
+      function GetCurrent: TBLGlyphRunEntry<T>; inline;
+    public
+      constructor Create(const AHandle: _PBLGlyphRun);
+      function MoveNext: Boolean; inline;
+
+      property Current: TBLGlyphRunEntry<T> read GetCurrent;
+    end;
+  private type
+    TEnumerable<T: record> = record
+    private
+      FHandle: _PBLGlyphRun;
+    public
+      constructor Create(const AHandle: _PBLGlyphRun);
+      function GetEnumerator: TEnumerator<T>;
+    end;
+  private
+    FHandle: BLGlyphRun;
+    function GetSize: Integer; inline;
+    procedure SetSize(const AValue: Integer); inline;
+    function GetPlacementType: TBLGlyphPlacementType; inline;
+    procedure SetPlacementType(const AValue: TBLGlyphPlacementType); inline;
+    function GetFlags: TBLGlyphRunFlags; inline;
+    procedure SetFlags(const AValue: TBLGlyphRunFlags); inline;
+    function GetIsEmpty: Boolean; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+    procedure SetGlyphData(const AData: PWord); overload; inline;
+    procedure SetGlyphData(const AData: PCardinal); overload; inline;
+    procedure SetGlyphData(const AData: Pointer; const AAdvance: Integer); overload; inline;
+    procedure ResetGlyphIdData; inline;
+    procedure SetPlacementData(const AData: Pointer; const AAdvance: Integer); inline;
+    procedure ResetPlacementData; inline;
+
+    { Support for..in enumeration of the glyphs in the run.
+      The type parameter TPlacement of each entry should be a type that is
+      compatible with the PlacementType property.
+
+      Example:
+
+      var
+        GlyphRun: TBLGlyphRun;
+        Entry: TBLGlyphRunEntry<TBLPoint>;
+      begin
+        GlyphRun := ...;
+        for Entry in GlyphRun.Entries<TBLPoint> do
+          ...
+      end; }
+    function Entries<TPlacement: record>: TEnumerable<TPlacement>;
+
+    { Glyph id data (abstract, incremented by GlyphAdvance). }
+    property GlyphData: Pointer read FHandle.glyphData write FHandle.glyphData;
+
+    { Glyph placement data (abstract, incremented by PlacementAdvance). }
+    property PlacementData: Pointer read FHandle.placementData write FHandle.placementData;
+
+    { Size of the glyph-run in glyph units. }
+    property Size: Integer read GetSize write SetSize;
+
+    { Size of a GlyphId - must be either 2 (UInt16) or 4 (UInt32) bytes.
+
+      Blend2D always uses 32-bit glyph-ids, thus the glyph-run returned
+      by IBLGlyphBuffer has always set GlyphSize to 4. The possibility to
+      render glyphs of size 2 is strictly for compatibility with text shapers
+      that use 16-bit glyphs, which is sufficient for TrueType and OpenType
+      fonts.}
+    property GlyphSize: Byte read FHandle.glyphSize write FHandle.glyphSize;
+
+    { Type of placement }
+    property PlacementType: TBLGlyphPlacementType read GetPlacementType write SetPlacementType;
+
+    { Advance of GlyphData array. }
+    property GlyphAdvance: Shortint read FHandle.glyphAdvance write FHandle.glyphAdvance;
+
+    { Glyph-run flags. }
+    property Flags: TBLGlyphRunFlags read GetFlags write SetFlags;
+
+    property IsEmpty: Boolean read GetIsEmpty;
+  end;
+  PBLGlyphRun = ^TBLGlyphRun;
+
+{ ============================================================================
+   [BLFontFaceInfo]
+  ============================================================================ }
+
+type
+  { Information of IBLFontFace. }
+  TBLFontFaceInfo = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontFaceInfo;
+    function GetFaceType: TBLFontFaceType; inline;
+    procedure SetFaceType(const AValue: TBLFontFaceType); inline;
+    function GetOutlineType: TBLFontOutlineType; inline;
+    procedure SetOutlineType(const AValue: TBLFontOutlineType); inline;
+    function GetGlyphCount: Integer; inline;
+    procedure SetGlyphCount(const AValue: Integer); inline;
+    function GetFaceFlags: TBLFontFaceFlags; inline;
+    procedure SetFaceFlags(const AValue: TBLFontFaceFlags); inline;
+    function GetDiagFlags: TBLFontFaceDiagFlags; inline;
+    procedure SetDiagFlags(const AValue: TBLFontFaceDiagFlags); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    { Font-face type }
+    property FaceType: TBLFontFaceType read GetFaceType write SetFaceType;
+
+    { Type of outlines used by the font-face }
+    property OutlineType: TBLFontOutlineType read GetOutlineType write SetOutlineType;
+
+    { Number of glyphs provided by this font-face. }
+    property GlyphCount: Integer read GetGlyphCount write SetGlyphCount;
+
+    { Revision (read from 'head' table, represented as 16.16 fixed point). }
+    property Revision: Cardinal read FHandle.revision write FHandle.revision;
+
+    { Face-face index in a TTF/OTF collection or zero if not part of a collection. }
+    property FaceIndex: Integer read FHandle.faceIndex write FHandle.faceIndex;
+
+    { Font-face flags }
+    property FaceFlags: TBLFontFaceFlags read GetFaceFlags write SetFaceFlags;
+
+    { Font-face diagnostic flags }
+    property DiagFlags: TBLFontFaceDiagFlags read GetDiagFlags write SetDiagFlags;
+  end;
+  PBLFontFaceInfo = ^TBLFontFaceInfo;
+
+{ ============================================================================
+   [BLFontQueryProperties]
+  ============================================================================ }
+
+type
+  { Properties that can be used to query IBLFont and IBLFontFace. }
+  TBLFontQueryProperties = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontQueryProperties;
+    function GetStyle: TBLFontStyle; inline;
+    procedure SetStyle(const AValue: TBLFontStyle); inline;
+    function GetWeight: TBLFontWeight; inline;
+    procedure SetWeight(const AValue: TBLFontWeight); inline;
+    function GetStretch: TBLFontStretch; inline;
+    procedure SetStretch(const AValue: TBLFontStretch); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    { Font style }
+    property Style: TBLFontStyle read GetStyle write SetStyle;
+
+    { Font weight }
+    property Weight: TBLFontWeight read GetWeight write SetWeight;
+
+    { Font stretch }
+    property Stretch: TBLFontStretch read GetStretch write SetStretch;
+  end;
+
+{ ============================================================================
+   [BLFontTable]
+  ============================================================================ }
+
+type
+  { A read only data that represents a font table or its sub-table. }
+  TBLFontTable = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontTable;
+    function GetSize: Integer; inline;
+    procedure SetSize(const AValue: Integer); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AData: Pointer; const ASize: Integer); overload; inline;
+
+    { Pointer to the beginning of the data }
+    property Data: Pointer read FHandle.data write FHandle.data;
+
+    { Size of Data in bytes. }
+    property Size: Integer read GetSize write SetSize;
+  end;
+  PBLFontTable = ^TBLFontTable;
+
+{ ============================================================================
+   [BLFontFeature]
+  ============================================================================ }
+
+type
+  { Associates a value with a generic font feature where Tag describes the
+    feature (as provided by the font) and Value describes its value. Some
+    features only allow boolean values 0 and 1 and some also allow higher
+    values up to 65535.
+
+    Registered OpenType features:
+    - https://docs.microsoft.com/en-us/typography/opentype/spec/featuretags
+    - https://helpx.adobe.com/typekit/using/open-type-syntax.html }
+  TBLFontFeature = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontFeature;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    { Feature tag (32-bit). }
+    property Tag: TBLTag read FHandle.tag write FHandle.tag;
+
+    { Feature value (should not be greater than 65535). }
+    property Value: Cardinal read FHandle.value write FHandle.value;
+  end;
+  PBLFontFeature = ^TBLFontFeature;
+
+{ ============================================================================
+   [BLFontVariation]
+  ============================================================================ }
+
+type
+  { Associates a value with a font variation feature where Tag describes
+    variation axis and Value defines its value. }
+  TBLFontVariation = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontVariation;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    { Variation tag (32-bit). }
+    property Tag: TBLTag read FHandle.tag write FHandle.tag;
+
+    { Variation value. }
+    property Value: Single read FHandle.value write FHandle.value;
+  end;
+  PBLFontVariation = ^TBLFontVariation;
+
+{ ============================================================================
+   [BLFontUnicodeCoverage]
+  ============================================================================ }
+
+type
+  { Font unicode coverage.
+
+    Unicode coverage describes which unicode characters are provided by a font.
+    Blend2D accesses this information by reading "OS/2" table, if available. }
+  TBLFontUnicodeCoverage = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontUnicodeCoverage;
+    function GetIsEmpty: Boolean; inline;
+    function GetBit(const AIndex: TBLFontUnicodeCoverageIndex): Boolean;
+    procedure SetBit(const AIndex: TBLFontUnicodeCoverageIndex; const AValue: Boolean); overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLFontUnicodeCoverage): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLFontUnicodeCoverage): Boolean; inline; static;
+  public
+    procedure Reset; inline;
+    procedure SetBit(const AIndex: TBLFontUnicodeCoverageIndex); overload; inline;
+    procedure ClearBit(const AIndex: TBLFontUnicodeCoverageIndex); inline;
+
+    property IsEmpty: Boolean read GetIsEmpty;
+    property Bits[const AIndex: TBLFontUnicodeCoverageIndex]: Boolean read GetBit write SetBit;
+  end;
+  PBLFontUnicodeCoverage = ^TBLFontUnicodeCoverage;
+
+{ ============================================================================
+   [BLFontPanose]
+  ============================================================================ }
+
+type
+  TBLFontPanoseText = record
+    FamilyKind: Byte;
+    SerifStyle: Byte;
+    Weight: Byte;
+    Proportion: Byte;
+    Contrast: Byte;
+    StrokeVariation: Byte;
+    ArmStyle: Byte;
+    Letterform: Byte;
+    Midline: Byte;
+    XHeight: Byte
+  end;
+
+type
+  TBLFontPanoseScript = record
+    FamilyKind: Byte;
+    ToolKind: Byte;
+    Weight: Byte;
+    Spacing: Byte;
+    AspectRatio: Byte;
+    Contrast: Byte;
+    Topology: Byte;
+    Form: Byte;
+    Finials: Byte;
+    XAscent: Byte;
+  end;
+
+type
+  TBLFontPanoseDecorative = record
+    FamilyKind: Byte;
+    DecorativeClass: Byte;
+    Weight: Byte;
+    Aspect: Byte;
+    Contrast: Byte;
+    SerifVariant: Byte;
+    Treatment: Byte;
+    Lining: Byte;
+    Topology: Byte;
+    CharacterRange: Byte;
+  end;
+
+type
+  TBLFontPanoseSymbol = record
+    FamilyKind: Byte;
+    SymbolKind: Byte;
+    Weight: Byte;
+    Spacing: Byte;
+    AspectRatioAndContrast: Byte;
+    AspectRatio94: Byte;
+    AspectRatio119: Byte;
+    AspectRatio157: Byte;
+    AspectRatio163: Byte;
+    AspectRatio211: Byte;
+  end;
+
+type
+  { Scaled TBLFontDesignMetrics based on font size and other properties. }
+  TBLFontPanose = record
+  {$REGION 'Internal Declarations'}
+  private
+    function GetIsEmpty: Boolean; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    property IsEmpty: Boolean read GetIsEmpty;
+  public
+    case Integer of
+      0: (Data: array [0..9] of Byte);
+      1: (FamilyKind: Byte);
+      2: (Text: TBLFontPanoseText);
+      3: (Script: TBLFontPanoseScript);
+      4: (Decorative: TBLFontPanoseDecorative);
+      5: (Symbol: TBLFontPanoseSymbol);
+  end;
+  PBLFontPanose = ^TBLFontPanose;
+
+{ ============================================================================
+   [BLFontMatrix]
+  ============================================================================ }
+
+type
+  { 2x2 transformation matrix used by IBLFont. It's similar to TBLMatrix2D,
+    however, it doesn't provide a translation part as it's assumed to be zero. }
+  TBLFontMatrix = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontMatrix;
+    function GetElement(const AIndex: Integer): Double; inline;
+    procedure SetElement(const AIndex: Integer; const AValue: Double); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AM00, AM01, AM10, AM11: Double); overload; inline;
+
+    property Elements[const AIndex: Integer]: Double read GetElement write SetElement; default;
+    property M00: Double read FHandle.m00 write FHandle.m00;
+    property M01: Double read FHandle.m01 write FHandle.m01;
+    property M10: Double read FHandle.m10 write FHandle.m10;
+    property M11: Double read FHandle.m11 write FHandle.m11;
+  end;
+  PBLFontMatrix = ^TBLFontMatrix;
+
+function BLFontMatrix(const AM00, AM01, AM10, AM11: Double): TBLFontMatrix; inline;
+
+{ ============================================================================
+   [BLFontMetrics]
+  ============================================================================ }
+
+type
+  { Scaled TBLFontDesignMetrics based on font size and other properties. }
+  TBLFontMetrics = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontMetrics;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    { Font ascent (horizontal orientation). }
+    property Ascent: Single read FHandle.ascent write FHandle.ascent;
+
+    { Font ascent (vertical orientation). }
+    property VAscent: Single read FHandle.vAscent write FHandle.vAscent;
+
+    { Font descent (horizontal orientation). }
+    property Descent: Single read FHandle.descent write FHandle.descent;
+
+    { Font descent (vertical orientation). }
+    property VDescent: Single read FHandle.vDescent write FHandle.vDescent;
+
+    { Line gap. }
+    property LineGap: Single read FHandle.lineGap write FHandle.lineGap;
+
+    { Distance between the baseline and the mean line of lower-case letters. }
+    property XHeight: Single read FHandle.xHeight write FHandle.xHeight;
+
+    { Maximum height of a capital letter above the baseline.}
+    property CapHeight: Single read FHandle.capHeight write FHandle.capHeight;
+
+    { Minimum x, reported by the font. }
+    property XMin: Single read FHandle.xMin write FHandle.xMin;
+
+    { Minimum y, reported by the font. }
+    property YMin: Single read FHandle.yMin write FHandle.yMin;
+
+    { Maximum x, reported by the font. }
+    property XMax: Single read FHandle.xMax write FHandle.xMax;
+
+    { Maximum y, reported by the font. }
+    property YMax: Single read FHandle.yMax write FHandle.yMax;
+
+    { Text underline position. }
+    property UnderlinePosition: Single read FHandle.underlinePosition write FHandle.underlinePosition;
+
+    { Text underline thickness. }
+    property UnderlineThickness: Single read FHandle.underlineThickness write FHandle.underlineThickness;
+
+    { Text strikethrough position. }
+    property StrikethroughPosition: Single read FHandle.strikethroughPosition write FHandle.strikethroughPosition;
+
+    { Text strikethrough thickness. }
+    property StrikethroughThickness: Single read FHandle.strikethroughThickness write FHandle.strikethroughThickness;
+  end;
+  PBLFontMetrics = ^TBLFontMetrics;
+
+{ ============================================================================
+   [BLFontDesignMetrics]
+  ============================================================================ }
+
+type
+  { Design metrics of a font.
+
+    Design metrics is information that IBLFontFace collected directly from the
+    font data. It means that all fields are measured in font design units.
+
+    When a new IBLFont instance is created a scaled metrics IBLFontMetrics is
+    automatically calculated from IBLFontDesignMetrics including other members
+    like transformation, etc... }
+  TBLFontDesignMetrics = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontDesignMetrics;
+    function GetGlyphBoundingBox: TBLBoxI; inline;
+    procedure SetGlyphBoundingBox(const AValue: TBLBoxI); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    { Units per EM square. }
+    property UnitsPerEm: Integer read FHandle.unitsPerEm write FHandle.unitsPerEm;
+
+    { Lowest readable size in pixels. }
+    property LowestPPEM: Integer read FHandle.lowestPPEM write FHandle.lowestPPEM;
+
+    { Line gap. }
+    property LineGap: Integer read FHandle.lineGap write FHandle.lineGap;
+
+    { Distance between the baseline and the mean line of lower-case letters. }
+    property XHeight: Integer read FHandle.xHeight write FHandle.xHeight;
+
+    { Maximum height of a capital letter above the baseline. }
+    property CapHeight: Integer read FHandle.capHeight write FHandle.capHeight;
+
+    { Ascent (horizontal layout). }
+    property Ascent: Integer read FHandle.ascent write FHandle.ascent;
+
+    { Ascent (vertical layout). }
+    property VAscent: Integer read FHandle.vAscent write FHandle.vAscent;
+
+    { Descent (horizontal layout). }
+    property Descent: Integer read FHandle.descent write FHandle.descent;
+
+    { Descent (vertical layout). }
+    property VDescent: Integer read FHandle.vDescent write FHandle.vDescent;
+
+    { Minimum leading-side bearing (horizontal layout). }
+    property HMinLSB: Integer read FHandle.hMinLSB write FHandle.hMinLSB;
+
+    { Minimum leading-side bearing (vertical layout). }
+    property VMinLSB: Integer read FHandle.vMinLSB write FHandle.vMinLSB;
+
+    { Minimum trailing-side bearing (horizontal layout). }
+    property HMinTSB: Integer read FHandle.hMinTSB write FHandle.hMinTSB;
+
+    { Minimum trailing-side bearing (vertical layout). }
+    property VMinTSB: Integer read FHandle.vMinTSB write FHandle.vMinTSB;
+
+    { Maximum advance (horizontal layout). }
+    property HMaxAdvance: Integer read FHandle.hMaxAdvance write FHandle.hMaxAdvance;
+
+    { Maximum advance (vertical layout). }
+    property VMaxAdvance: Integer read FHandle.vMaxAdvance write FHandle.vMaxAdvance;
+
+    { Aggregated bounding box of all glyphs in the font.
+      This value is reported by the face so it's not granted to be true. }
+    property GlyphBoundingBox: TBLBoxI read GetGlyphBoundingBox write SetGlyphBoundingBox;
+
+    { Minimum x, reported by the font. }
+    property XMin: Integer read FHandle.glyphBoundingBox.x0 write FHandle.glyphBoundingBox.x0;
+
+    { Minimum y, reported by the font. }
+    property YMin: Integer read FHandle.glyphBoundingBox.y0 write FHandle.glyphBoundingBox.y0;
+
+    { Maximum x, reported by the font. }
+    property XMax: Integer read FHandle.glyphBoundingBox.x1 write FHandle.glyphBoundingBox.x1;
+
+    { Maximum y, reported by the font. }
+    property YMax: Integer read FHandle.glyphBoundingBox.y1 write FHandle.glyphBoundingBox.y1;
+
+
+    { Text underline position. }
+    property UnderlinePosition: Integer read FHandle.underlinePosition write FHandle.underlinePosition;
+
+    { Text underline thickness. }
+    property UnderlineThickness: Integer read FHandle.underlineThickness write FHandle.underlineThickness;
+
+    { Text strikethrough position. }
+    property StrikethroughPosition: Integer read FHandle.strikethroughPosition write FHandle.strikethroughPosition;
+
+    { Text strikethrough thickness. }
+    property StrikethroughThickness: Integer read FHandle.strikethroughThickness write FHandle.strikethroughThickness;
+  end;
+  PBLFontDesignMetrics = ^TBLFontDesignMetrics;
+
+{ ============================================================================
+   [BLTextMetrics]
+  ============================================================================ }
+
+type
+  { Text metrics. }
+  TBLTextMetrics = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLTextMetrics;
+    function GetAdvance: TBLPoint; inline;
+    procedure SetAdvance(const AValue: TBLPoint); inline;
+    function GetLeadingBearing: TBLPoint; inline;
+    procedure SetLeadingBearing(const AValue: TBLPoint); inline;
+    function GetTrailingBearing: TBLPoint; inline;
+    procedure SetTrailingBearing(const AValue: TBLPoint); inline;
+    function GetBoundingBox: TBLBox; inline;
+    procedure SetBoundingBox(const AValue: TBLBox); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    property Advance: TBLPoint read GetAdvance write SetAdvance;
+    property LeadingBearing: TBLPoint read GetLeadingBearing write SetLeadingBearing;
+    property TrailingBearing: TBLPoint read GetTrailingBearing write SetTrailingBearing;
+    property BoundingBox: TBLBox read GetBoundingBox write SetBoundingBox;
+  end;
+  PBLTextMetrics = ^TBLTextMetrics;
+
+{$ENDREGION 'Font Defs'}
+
+{$REGION 'Glyph Buffer'}
+
+{ ============================================================================
+   [BLGlyphBuffer]
+  ============================================================================ }
+
+type
+  { Glyph buffer.
+
+    Can hold either text or glyphs and provides basic memory management that is
+    used for text shaping, character to glyph mapping, glyph substitution, and
+    glyph positioning.
+
+    Glyph buffer provides two separate buffers called 'primary' and 'secondary'
+    that serve different purposes during processing. Primary buffer always holds
+    actual text/glyph array, and secondary buffer is either used as a scratch
+    buffer during glyph substitution or to hold glyph positions after the
+    processing is complete and glyph positions were calculated. }
+  IBLGlyphBuffer = interface
+  ['{0B892B22-C3B5-434D-854C-FBD0FD431B7B}']
+    {$REGION 'Internal Declarations'}
+    function GetIsEmpty: Boolean;
+    function GetSize: Integer;
+    function GetFlags: TBLGlyphRunFlags;
+    function GetContent: PCardinal;
+    function GetInfoData: PBLGlyphInfo;
+    function GetPlacementData: PBLGlyphPlacement;
+    function GetGlyphRun: PBLGlyphRun;
+    function GetHasText: Boolean;
+    function GetHasGlyphs: Boolean;
+    function GetHasInvalidChars: Boolean;
+    function GetHasUndefinedChars: Boolean;
+    function GetHasInvalidFontData: Boolean;
+    function GetHandle: PBLGlyphBufferCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    { Resets the IBLGlyphBuffer into its construction state. The content will
+      be cleared and allocated memory released. }
+    procedure Reset;
+
+    { Clears the content of IBLGlyphBuffer without releasing internal buffers. }
+    procedure Clear;
+
+    { Assigns a text content of this IBLGlyphBuffer. }
+    procedure SetText(const AText: String); overload;
+    procedure SetText(const AText: UTF8String); overload;
+    procedure SetText(const AText: UCS4String); overload;
+
+    { Assigns a text content of this IBLGlyphBuffer.
+
+      This is a generic function that accepts Pointer data, which is specified
+      by AEncoding. The ALength argument depends on encoding as well. If the
+      encoding specifies byte string (Latin1 or UTF8) then it's bytes, if the
+      encoding specifies UTF16 or UTF32 then it would describe the number of
+      UInt16 or UInt32 code points, respectively. }
+    procedure SetText(const AText: Pointer; const ALength: Integer;
+      const AEncoding: TBLTextEncoding); overload;
+
+    { Assigns glyph content of this IBLGlyphBuffer from the given AGlyphData. }
+    procedure SetGlyphs(const AGlyphData: TArray<Cardinal>); overload;
+    procedure SetGlyphs(const AGlyphData: PCardinal; const ALength: Integer); overload;
+
+    { Assigns glyph content of this IBLGlyphBuffer`from an array of glyphs or
+      from a foreign record that contains glyphs and possibly other members that
+      have to be skipped. The AGlyphIdSize can be either 16-bit (2) or 32-bit (4).
+      The last parameter AGlyphAdvance specifies how many bytes to advance after
+      a glyph value is read. }
+    procedure SetGlyphs(const AGlyphData: Pointer; const ASize: Integer;
+      const AGlyphIdSize, AGlyphAdvance: Integer); overload;
+
+    { Tests whether the glyph-buffer has AFlag set. }
+    function HasFlag(const AFlag: TBLGlyphRunFlag): Boolean;
+
+    property IsEmpty: Boolean read GetIsEmpty;
+    property Size: Integer read GetSize;
+    property Flags: TBLGlyphRunFlags read GetFlags;
+    property Content: PCardinal read GetContent;
+    property InfoData: PBLGlyphInfo read GetInfoData;
+    property PlacementData: PBLGlyphPlacement read GetPlacementData;
+    property GlyphRun: PBLGlyphRun read GetGlyphRun;
+
+    { Tests whether the buffer contains unicode data. }
+    property HasText: Boolean read GetHasText;
+
+    { Tests whether the buffer contains glyph-id data. }
+    property HasGlyphs: Boolean read GetHasGlyphs;
+
+    { Tests whether the input string contained invalid characters (unicode
+      encoding errors). }
+    property HasInvalidChars: Boolean read GetHasInvalidChars;
+
+    { Tests whether the input string contained undefined characters that weren't
+      mapped properly to glyphs. }
+    property HasUndefinedChars: Boolean read GetHasUndefinedChars;
+
+    { Tests whether one or more operation was terminated before completion
+      because of invalid data in a font. }
+    property HasInvalidFontData: Boolean read GetHasInvalidFontData;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLGlyphBufferCore read GetHandle;
+  end;
+
+type
+  { Implements IBLGlyphBuffer }
+  TBLGlyphBuffer = class(TInterfacedObject, IBLGlyphBuffer)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLGlyphBufferCore;
+  protected
+    { IBLGlyphBuffer }
+    function GetIsEmpty: Boolean;
+    function GetSize: Integer;
+    function GetFlags: TBLGlyphRunFlags;
+    function GetContent: PCardinal;
+    function GetInfoData: PBLGlyphInfo;
+    function GetPlacementData: PBLGlyphPlacement;
+    function GetGlyphRun: PBLGlyphRun;
+    function GetHasText: Boolean;
+    function GetHasGlyphs: Boolean;
+    function GetHasInvalidChars: Boolean;
+    function GetHasUndefinedChars: Boolean;
+    function GetHasInvalidFontData: Boolean;
+    function GetHandle: PBLGlyphBufferCore;
+
+    procedure Reset;
+    procedure Clear;
+
+    procedure SetText(const AText: String); overload;
+    procedure SetText(const AText: UTF8String); overload;
+    procedure SetText(const AText: UCS4String); overload;
+    procedure SetText(const AText: Pointer; const ALength: Integer;
+      const AEncoding: TBLTextEncoding); overload;
+
+    procedure SetGlyphs(const AGlyphData: TArray<Cardinal>); overload;
+    procedure SetGlyphs(const AGlyphData: PCardinal; const ALength: Integer); overload;
+    procedure SetGlyphs(const AGlyphData: Pointer; const ASize: Integer;
+      const AGlyphIdSize, AGlyphAdvance: Integer); overload;
+
+    function HasFlag(const AFlag: TBLGlyphRunFlag): Boolean;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create;
+    destructor Destroy; override;
+  end;
+
+{$ENDREGION 'Glyph Buffer'}
+
+{$REGION 'Font'}
+
+{ ============================================================================
+   [BLFontData]
+  ============================================================================ }
+
+type
+  IBLFontData = interface;
+
+  { This event is called when IBLFontData.InitializeFromData is used and the
+    font data is destroyed. }
+  TBLFontDataDestroyEvent = procedure (const AFontData: IBLFontData) of object;
+
+  { Font data }
+  IBLFontData = interface
+  ['{988C31B8-A00C-4BD0-98D9-FDF2EF6D8CAA}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetFaceType: TBLFontFaceType;
+    function GetFaceCount: Integer;
+    function GetFlags: TBLFontDataFlags;
+    function GetIsCollection: Boolean;
+    function GetHandle: PBLFontDataCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    { Initializes an IBLFontData from a file specified by the given AFilename.
+
+      The AReadFlags argument allows to specify flags that will be passed to
+      IBLFileSystem.ReadFile to read the content of the file. It's possible to
+      use memory mapping to get its content, which is the recommended way for
+      reading system fonts. The best combination is to use the
+      TBLFileReadFlag.MmapEnabled flag combined with
+      TBLFileReadFlag.MmapAvoidSmall. This combination means to try to use
+      memory mapping only when the size of the font is greater than a minimum
+      value (determined by Blend2D), and would fallback to a regular open/read
+      in case the memory mapping is not possible or failed for some other
+      reason. Please note that not all files can be memory mapped so the
+      TBLFileReadFlag.MmapNoFallback flag is not recommended. }
+    procedure InitializeFromFile(const AFilename: String;
+      const AReadFlags: TBLFileReadFlags = []);
+
+    { Initializes an IBLFontData from the given AData.
+
+      The given AData would be weak copied on success so the given array can be
+      safely destroyed after the function returns.
+
+      The weak copy of the passed AData is internal and there is no API to
+      access it after the function returns. The reason for making it internal
+      is that multiple implementations of IBLFontData may exist and some can
+      only store data at table level, so Blend2D doesn't expose the detail about
+      how the data is stored. }
+    procedure InitializeFromData(const AData: TBytes); overload;
+
+    { Creates IBLFontData from the given AData of the given ASize.
+
+      AData must stay alive as long as this object is alive.
+      Optionally an AOnDestroy event can be used as a notifier that will be
+      called when the data is no longer needed. }
+    procedure InitializeFromData(const AData: Pointer; const ASize: Integer;
+      const AOnDestroy: TBLFontDataDestroyEvent = nil); overload;
+
+    procedure Reset;
+    function Equals(const AOther: IBLFontData): Boolean;
+
+    function GetTags(const AFaceIndex: Integer): TArray<TBLTag>;
+    function QueryTable(const AFaceIndex: Integer; const ATag: TBLTag;
+      out ATable: TBLFontTable): Integer;
+    function QueryTables(const AFaceIndex: Integer; const ATags: TArray<TBLTag>;
+      out ATables: TArray<TBLFontTable>): Integer;
+
+    { Whether the font data is a built-in null instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Tests whether the font data is empty (which the same as IsNone in this
+      case). }
+    property IsEmpty: Boolean read GetIsNone;
+
+    { Type of font-face that this data describes.
+
+      It doesn't matter if the content is a single font or a collection. In
+      any case the FaceType would always return the type of the font-face
+      that will be created by IBLFontFace.CreateFromData. }
+    property FaceType: TBLFontFaceType read GetFaceType;
+
+    { The number of faces of this font-data.
+
+      If the data is not initialized the result would be always zero. If the
+      data is initialized to a single font it would be 1, and if the data is
+      initialized to a font collection then the return would correspond to
+      the number of font-faces within that collection.
+
+      You should not use FaceCount to check whether the font is a collection as
+      it's possible to have a font-collection with just a single font. Using
+      IsCollection is more reliable and would always return the right value. }
+    property FaceCount: Integer read GetFaceCount;
+
+    { Font-data flags }
+    property Flags: TBLFontDataFlags read GetFlags;
+
+    { Whether this font-data is a font-collection. }
+    property IsCollection: Boolean read GetIsCollection;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLFontDataCore read GetHandle;
+  end;
+
+type
+  { Implements IBLFontData }
+  TBLFontData = class(TInterfacedObject, IBLFontData)
+  {$REGION 'Internal Declarations'}
+  private type
+    TDestroyData = record
+      FontData: IBLFontData;
+      Event: TBLFontDataDestroyEvent;
+    end;
+    PDestroyData = ^TDestroyData;
+  private
+    FHandle: BLFontDataCore;
+    FIsReference: Boolean;
+  private
+    class procedure DoDestroy(impl, destroyData: Pointer); cdecl; static;
+  protected
+    { IBLFontData }
+    function GetIsNone: Boolean;
+    function GetFaceType: TBLFontFaceType;
+    function GetFaceCount: Integer;
+    function GetFlags: TBLFontDataFlags;
+    function GetIsCollection: Boolean;
+    function GetHandle: PBLFontDataCore;
+
+    procedure InitializeFromFile(const AFilename: String;
+      const AReadFlags: TBLFileReadFlags = []);
+
+    procedure InitializeFromData(const AData: TBytes); overload;
+    procedure InitializeFromData(const AData: Pointer; const ASize: Integer;
+      const AOnDestroy: TBLFontDataDestroyEvent = nil); overload;
+
+    procedure Reset;
+    function Equals(const AOther: IBLFontData): Boolean; reintroduce; overload;
+
+    function GetTags(const AFaceIndex: Integer): TArray<TBLTag>;
+    function QueryTable(const AFaceIndex: Integer; const ATag: TBLTag;
+      out ATable: TBLFontTable): Integer;
+    function QueryTables(const AFaceIndex: Integer; const ATags: TArray<TBLTag>;
+      out ATables: TArray<TBLFontTable>): Integer;
+  private
+    constructor Create(const AHandle: BLFontDataCore;
+      const AIsReference: Boolean); overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create; overload;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+
+{ ============================================================================
+   [BLFontFace]
+  ============================================================================ }
+
+type
+  { Font face }
+  IBLFontFace = interface
+  ['{D51BEBAD-EB2A-41CA-B76C-5773E696CA80}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetWeight: TBLFontWeight;
+    function GetStretch: TBLFontStretch;
+    function GetStyle: TBLFontStyle;
+    function GetFaceInfo: TBLFontFaceInfo;
+    function GetFaceType: TBLFontFaceType;
+    function GetOutlineType: TBLFontOutlineType;
+    function GetFaceIndex: Integer;
+    function GetFaceFlags: TBLFontFaceFlags;
+    function GetHasTypographicNames: Boolean;
+    function GetHasTypographicMetrics: Boolean;
+    function GetHasCharToGlyphMapping: Boolean;
+    function GetHasHorizontalMetrics: Boolean;
+    function GetHasVerticalMetrics: Boolean;
+    function GetHasHorizontalKerning: Boolean;
+    function GetHasVerticalKerning: Boolean;
+    function GetHasOpenTypeFeatures: Boolean;
+    function GetHasPanoseData: Boolean;
+    function GetHasUnicodeCoverage: Boolean;
+    function GetHasBaselineYAt0: Boolean;
+    function GetHasLSBPointXAt0: Boolean;
+    function GetHasVariationSequences: Boolean;
+    function GetHasOpenTypeVariations: Boolean;
+    function GetIsSymbolFont: Boolean;
+    function GetIsLastResortFont: Boolean;
+    function GetDiagFlags: TBLFontFaceDiagFlags;
+    function GetUniqueId: TBLUniqueId;
+    function GetData: IBLFontData;
+    function GetFullName: String;
+    function GetFamilyName: String;
+    function GetSubfamilyName: String;
+    function GetPostScriptName: String;
+    function GetDesignMetrics: TBLFontDesignMetrics;
+    function GetUnitsPerEm: Integer;
+    function GetPanose: TBLFontPanose;
+    function GetUnicodeCoverage: TBLFontUnicodeCoverage;
+    function GetHandle: PBLFontFaceCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    { Initializes an IBLFontFace from a file specified by AFileName.
+
+      This is a utility function that first creates a IBLFontData and then
+      calls InitializeFromData(FontData, 0). See IBLFontData.CreateFromFile
+      for more details, especially the use of AReadFlags is important for
+      system fonts.
+
+      This function offers a simplified creation of IBLFontFace directly
+      from a file, but doesn't provide as much flexibility as InitializeFromData
+      as it allows to specify a AFaceIndex, which can be used to load multiple
+      font-faces from a TrueType/OpenType collection. The use of
+      InitializeFromData is recommended for any serious font handling. }
+    procedure InitializeFromFile(const AFilename: String;
+      const AReadFlags: TBLFileReadFlags = []);
+
+    { Initializes an IBLFontFace from IBLFontData at the given AFaceIndex. }
+    procedure InitializeFromData(const AFontData: IBLFontData;
+      const AFaceIndex: Integer);
+
+    procedure Reset;
+    function Equals(const AOther: IBLFontFace): Boolean;
+
+    { Tests whether the font-face has a given AFlag set. }
+    function HasFaceFlag(const AFlag: TBLFontFaceFlag): Boolean;
+
+    { Whether the font face is a built-in null instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Tests whether the font face is empty (which the same as IsNone in this
+      case). }
+    property IsEmpty: Boolean read GetIsNone;
+
+    { Font weight (returns default weight in case this is a variable font). }
+    property Weight: TBLFontWeight read GetWeight;
+
+    { Font stretch (returns default weight in case this is a variable font). }
+    property Stretch: TBLFontStretch read GetStretch;
+
+    { Font style }
+    property Style: TBLFontStyle read GetStyle;
+
+    { Font-face information }
+    property FaceInfo: TBLFontFaceInfo read GetFaceInfo;
+
+    { Font-face type }
+    property FaceType: TBLFontFaceType read GetFaceType;
+
+    { Font-face outline type }
+    property OutlineType: TBLFontOutlineType read GetOutlineType;
+
+    { Zero-based index of this font-face.
+
+      Face index does only make sense if this face is part of a TrueType
+      or OpenType font collection. In that case the returned value would be
+      the index of this face in that collection. If the face is not part of a
+      collection then the returned value would always be zero. }
+    property FaceIndex: Integer read GetFaceIndex;
+
+    { Font-face flags }
+    property FaceFlags: TBLFontFaceFlags read GetFaceFlags;
+
+    { Tests whether the font-face uses typographic family and subfamily names. }
+    property HasTypographicNames: Boolean read GetHasTypographicNames;
+
+    { Tests whether the font-face uses typographic metrics. }
+    property HasTypographicMetrics: Boolean read GetHasTypographicMetrics;
+
+    { Tests whether the font-face provides character to glyph mapping. }
+    property HasCharToGlyphMapping: Boolean read GetHasCharToGlyphMapping;
+
+    { Tests whether the font-face has horizontal glyph metrics (advances, side
+      bearings). }
+    property HasHorizontalMetrics: Boolean read GetHasHorizontalMetrics;
+
+    { Tests whether the font-face has vertical glyph metrics (advances, side
+      bearings). }
+    property HasVerticalMetrics: Boolean read GetHasVerticalMetrics;
+
+    { Tests whether the font-face has a legacy horizontal kerning feature
+      ('kern' table with horizontal kerning data). }
+    property HasHorizontalKerning: Boolean read GetHasHorizontalKerning;
+
+    { Tests whether the font-face has a legacy vertical kerning feature ('kern'
+      table with vertical kerning data). }
+    property HasVerticalKerning: Boolean read GetHasVerticalKerning;
+
+    { Tests whether the font-face has OpenType features (GDEF, GPOS, GSUB). }
+    property HasOpenTypeFeatures: Boolean read GetHasOpenTypeFeatures;
+
+    { Tests whether the font-face has panose classification. }
+    property HasPanoseData: Boolean read GetHasPanoseData;
+
+    { Tests whether the font-face has unicode coverage information. }
+    property HasUnicodeCoverage: Boolean read GetHasUnicodeCoverage;
+
+    { Tests whether the font-face's baseline equals 0. }
+    property HasBaselineYAt0: Boolean read GetHasBaselineYAt0;
+
+    { Tests whether the font-face's left sidebearing point at `x` equals 0. }
+    property HasLSBPointXAt0: Boolean read GetHasLSBPointXAt0;
+
+    { Tests whether the font-face has unicode variation sequences feature. }
+    property HasVariationSequences: Boolean read GetHasVariationSequences;
+
+    { Tests whether the font-face has OpenType Font Variations feature. }
+    property HasOpenTypeVariations: Boolean read GetHasOpenTypeVariations;
+
+    { This is a symbol font. }
+    property IsSymbolFont: Boolean read GetIsSymbolFont;
+
+    { This is a last resort font. }
+    property IsLastResortFont: Boolean read GetIsLastResortFont;
+
+    { Font-face diagnostics flags }
+    property DiagFlags: TBLFontFaceDiagFlags read GetDiagFlags;
+
+    { A unique identifier describing this IBLFontFace. }
+    property UniqueId: TBLUniqueId read GetUniqueId;
+
+    { IBLFontData associated with this font-face. }
+    property Data: IBLFontData read GetData;
+
+    { Font full name }
+    property FullName: String read GetFullName;
+
+    { Family name }
+    property FamilyName: String read GetFamilyName;
+
+    { Font subfamily name }
+    property SubfamilyName: String read GetSubfamilyName;
+
+    { Font PostScript name }
+    property PostScriptName: String read GetPostScriptName;
+
+    { Design metrics of this IBLFontFace. }
+    property DesignMetrics: TBLFontDesignMetrics read GetDesignMetrics;
+
+    { Units per em, which are part of font's design metrics. }
+    property UnitsPerEm: Integer read GetUnitsPerEm;
+
+    { PANOSE classification of this IBLFontFace. }
+    property Panose: TBLFontPanose read GetPanose;
+
+    { Unicode coverage of this IBLFontFace.
+
+      The returned unicode-coverage is not calculated by Blend2D so in general
+      the value doesn't have to be correct. Use GetCharacterCoverage to get
+      a coverage calculated by Blend2D at character granularity. }
+    property UnicodeCoverage: TBLFontUnicodeCoverage read GetUnicodeCoverage;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLFontFaceCore read GetHandle;
+  end;
+
+type
+  { Implements IBLFontFace }
+  TBLFontFace = class(TInterfacedObject, IBLFontFace)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontFaceCore;
+    FData: IBLFontData;
+    FIsReference: Boolean;
+  protected
+    { IBLFontFace }
+    function GetIsNone: Boolean;
+    function GetWeight: TBLFontWeight;
+    function GetStretch: TBLFontStretch;
+    function GetStyle: TBLFontStyle;
+    function GetFaceInfo: TBLFontFaceInfo;
+    function GetFaceType: TBLFontFaceType;
+    function GetOutlineType: TBLFontOutlineType;
+    function GetFaceIndex: Integer;
+    function GetFaceFlags: TBLFontFaceFlags;
+    function GetHasTypographicNames: Boolean;
+    function GetHasTypographicMetrics: Boolean;
+    function GetHasCharToGlyphMapping: Boolean;
+    function GetHasHorizontalMetrics: Boolean;
+    function GetHasVerticalMetrics: Boolean;
+    function GetHasHorizontalKerning: Boolean;
+    function GetHasVerticalKerning: Boolean;
+    function GetHasOpenTypeFeatures: Boolean;
+    function GetHasPanoseData: Boolean;
+    function GetHasUnicodeCoverage: Boolean;
+    function GetHasBaselineYAt0: Boolean;
+    function GetHasLSBPointXAt0: Boolean;
+    function GetHasVariationSequences: Boolean;
+    function GetHasOpenTypeVariations: Boolean;
+    function GetIsSymbolFont: Boolean;
+    function GetIsLastResortFont: Boolean;
+    function GetDiagFlags: TBLFontFaceDiagFlags;
+    function GetUniqueId: TBLUniqueId;
+    function GetData: IBLFontData;
+    function GetFullName: String;
+    function GetFamilyName: String;
+    function GetSubfamilyName: String;
+    function GetPostScriptName: String;
+    function GetDesignMetrics: TBLFontDesignMetrics;
+    function GetUnitsPerEm: Integer;
+    function GetPanose: TBLFontPanose;
+    function GetUnicodeCoverage: TBLFontUnicodeCoverage;
+    function GetHandle: PBLFontFaceCore;
+
+    procedure InitializeFromFile(const AFilename: String;
+      const AReadFlags: TBLFileReadFlags = []);
+
+    procedure InitializeFromData(const AFontData: IBLFontData;
+      const AFaceIndex: Integer);
+
+    procedure Reset;
+    function Equals(const AOther: IBLFontFace): Boolean; reintroduce; overload;
+    function HasFaceFlag(const AFlag: TBLFontFaceFlag): Boolean;
+  private
+    constructor Create(const AHandle: BLFontFaceCore;
+      const AIsReference: Boolean); overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create; overload;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+
+{ ============================================================================
+   [BLFont]
+  ============================================================================ }
+
+type
+  { Font }
+  IBLFont = interface
+  ['{47ED75E4-8E6C-4D0E-95D9-6321CD4F8694}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetFaceType: TBLFontFaceType;
+    function GetFaceFlags: TBLFontFaceFlags;
+    function GetSize: Single;
+    function GetUnitsPerEm: Integer;
+    function GetFace: IBLFontFace;
+    function GetFeatures: TArray<TBLFontFeature>;
+    function GetVariations: TArray<TBLFontVariation>;
+    function GetWeight: TBLFontWeight;
+    function GetStretch: TBLFontStretch;
+    function GetStyle: TBLFontStyle;
+    function GetMatrix: TBLFontMatrix;
+    function GetMetrics: TBLFontMetrics;
+    function GetMetricsPtr: PBLFontMetrics;
+    function GetDesignMetrics: TBLFontDesignMetrics;
+    function GetHandle: PBLFontCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    procedure InitializeFromFace(const AFace: IBLFontFace;
+      const ASize: Single);
+
+    procedure Reset;
+    function Equals(const AOther: IBLFont): Boolean;
+
+    procedure Shape(const AGlyphBuffer: IBLGlyphBuffer);
+    procedure MapTextToGlyphs(const AGlyphBuffer: IBLGlyphBuffer); overload;
+    procedure MapTextToGlyphs(const AGlyphBuffer: IBLGlyphBuffer;
+      out AState: TBLGlyphMappingState); overload;
+
+    { TODO : Check when Blend2D updates APositioningFlags }
+    procedure PositionGlyphs(const AGlyphBuffer: IBLGlyphBuffer;
+      const APositioningFlags: Cardinal = $FFFFFFFF);
+
+    procedure ApplyKerning(const AGlyphBuffer: IBLGlyphBuffer);
+    procedure ApplyGSub(const AGlyphBuffer: IBLGlyphBuffer;
+      const AIndex: Integer; const ALookups: TBLBitWord);
+    procedure ApplyGPos(const AGlyphBuffer: IBLGlyphBuffer;
+      const AIndex: Integer; const ALookups: TBLBitWord);
+    function GetTextMetrics(const AGlyphBuffer: IBLGlyphBuffer): TBLTextMetrics;
+
+    function GetGlyphBounds(const AGlyphData: PCardinal;
+      const AGlyphAdvance, ACount: Integer): TArray<TBLBoxI>;
+    function GetGlyphAdvances(const AGlyphData: PCardinal;
+      const AGlyphAdvance, ACount: Integer): TArray<TBLGlyphPlacement>;
+    function GetGlyphOutlines(const AGlyphId: Cardinal;
+      const ASink: TBLPathSinkEvent): IBLPath; overload;
+    function GetGlyphOutlines(const AGlyphId: Cardinal;
+      const AUserMatrix: TBLMatrix2D;
+      const ASink: TBLPathSinkEvent): IBLPath; overload;
+    function GetGlyphRunOutlines(const AGlyphRun: TBLGlyphRun;
+      const ASink: TBLPathSinkEvent): IBLPath; overload;
+    function GetGlyphRunOutlines(const AGlyphRun: TBLGlyphRun;
+      const AUserMatrix: TBLMatrix2D;
+      const ASink: TBLPathSinkEvent): IBLPath; overload;
+
+    { Whether the font is a built-in null instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { Tests whether the font is empty (which the same as IsNone in this case). }
+    property IsEmpty: Boolean read GetIsNone;
+
+    { Type of the font's associated font-face }
+    property FaceType: TBLFontFaceType read GetFaceType;
+
+    { Flags of the font }
+    property FaceFlags: TBLFontFaceFlags read GetFaceFlags;
+
+    { Size of the font }
+    property Size: Single read GetSize;
+
+    { The "units per em" (UPEM) of the font's associated font-face. }
+    property UnitsPerEm: Integer read GetUnitsPerEm;
+
+    { The font's associated font-face.
+      Returns the same font-face, which was passed to InitializeFromFace. }
+    property Face: IBLFontFace read GetFace;
+
+    { The features associated with the font. }
+    property Features: TArray<TBLFontFeature> read GetFeatures;
+
+    { The variations associated with the font. }
+    property Variations: TArray<TBLFontVariation> read GetVariations;
+
+    { The weight of the font. }
+    property Weight: TBLFontWeight read GetWeight;
+
+    { The stretch of the font. }
+    property Stretch: TBLFontStretch read GetStretch;
+
+    { The style of the font. }
+    property Style: TBLFontStyle read GetStyle;
+
+    { The 2x2 matrix of the font.
+
+      The returned TBLFontMatrix is used to scale fonts from design units
+      into user units. The matrix usually has a negative M11 member as
+      fonts use a different coordinate system than Blend2D. }
+    property Matrix: TBLFontMatrix read GetMatrix;
+
+    { The scaled metrics of the font.
+
+      The returned metrics is a scale of design metrics that match the font size
+      and its options. }
+    property Metrics: TBLFontMetrics read GetMetrics;
+    property MetricsPtr: PBLFontMetrics read GetMetricsPtr;
+
+    { The design metrics of the font.
+
+      The returned metrics is compatible with the metrics of IBLFontFace
+      associated with this font. }
+    property DesignMetrics: TBLFontDesignMetrics read GetDesignMetrics;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLFontCore read GetHandle;
+  end;
+
+type
+  { Implements IBLFont }
+  TBLFont = class(TInterfacedObject, IBLFont)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontCore;
+    FFace: IBLFontFace;
+    FSink: TBLPathSinkEvent;
+    FSinkPath: IBLPath;
+  private
+    class function DoSink(path: PBLPathCore; info: Pointer;
+      closure: Pointer): Cardinal; cdecl; static;
+  protected
+    { IBLFont }
+    function GetIsNone: Boolean;
+    function GetFaceType: TBLFontFaceType;
+    function GetFaceFlags: TBLFontFaceFlags;
+    function GetSize: Single;
+    function GetUnitsPerEm: Integer;
+    function GetFace: IBLFontFace;
+    function GetFeatures: TArray<TBLFontFeature>;
+    function GetVariations: TArray<TBLFontVariation>;
+    function GetWeight: TBLFontWeight;
+    function GetStretch: TBLFontStretch;
+    function GetStyle: TBLFontStyle;
+    function GetMatrix: TBLFontMatrix;
+    function GetMetrics: TBLFontMetrics;
+    function GetMetricsPtr: PBLFontMetrics;
+    function GetDesignMetrics: TBLFontDesignMetrics;
+    function GetHandle: PBLFontCore;
+
+    procedure InitializeFromFace(const AFace: IBLFontFace;
+      const ASize: Single);
+
+    procedure Reset;
+    function Equals(const AOther: IBLFont): Boolean; reintroduce; overload;
+
+    procedure Shape(const AGlyphBuffer: IBLGlyphBuffer);
+    procedure MapTextToGlyphs(const AGlyphBuffer: IBLGlyphBuffer); overload;
+    procedure MapTextToGlyphs(const AGlyphBuffer: IBLGlyphBuffer;
+      out AState: TBLGlyphMappingState); overload;
+
+    procedure PositionGlyphs(const AGlyphBuffer: IBLGlyphBuffer;
+      const APositioningFlags: Cardinal);
+
+    procedure ApplyKerning(const AGlyphBuffer: IBLGlyphBuffer);
+    procedure ApplyGSub(const AGlyphBuffer: IBLGlyphBuffer;
+      const AIndex: Integer; const ALookups: TBLBitWord);
+    procedure ApplyGPos(const AGlyphBuffer: IBLGlyphBuffer;
+      const AIndex: Integer; const ALookups: TBLBitWord);
+    function GetTextMetrics(const AGlyphBuffer: IBLGlyphBuffer): TBLTextMetrics;
+
+    function GetGlyphBounds(const AGlyphData: PCardinal;
+      const AGlyphAdvance, ACount: Integer): TArray<TBLBoxI>;
+    function GetGlyphAdvances(const AGlyphData: PCardinal;
+      const AGlyphAdvance, ACount: Integer): TArray<TBLGlyphPlacement>;
+    function GetGlyphOutlines(const AGlyphId: Cardinal;
+      const ASink: TBLPathSinkEvent): IBLPath; overload;
+    function GetGlyphOutlines(const AGlyphId: Cardinal;
+      const AUserMatrix: TBLMatrix2D;
+      const ASink: TBLPathSinkEvent): IBLPath; overload;
+    function GetGlyphRunOutlines(const AGlyphRun: TBLGlyphRun;
+      const ASink: TBLPathSinkEvent): IBLPath; overload;
+    function GetGlyphRunOutlines(const AGlyphRun: TBLGlyphRun;
+      const AUserMatrix: TBLMatrix2D;
+      const ASink: TBLPathSinkEvent): IBLPath; overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+
+{$ENDREGION 'Font'}
+
+{$REGION 'Font Manager'}
+
+{ ============================================================================
+   [BLFontManager]
+  ============================================================================ }
+
+type
+  { Font data }
+  IBLFontManager = interface
+  ['{A75AAED4-30E3-4A65-978F-590528AB2DCF}']
+    {$REGION 'Internal Declarations'}
+    function GetIsNone: Boolean;
+    function GetFaceCount: Integer;
+    function GetFamilyCount: Integer;
+    function GetHandle: PBLFontManagerCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    procedure Reset;
+    function Equals(const AOther: IBLFontManager): Boolean;
+
+    procedure Initialize;
+
+    { Whether the font manager contains the given font AFace. }
+    function HasFace(const AFace: IBLFontFace): Boolean;
+
+    { Adds a font AFace to the font manager. Does nothing if the manager already
+      contans the font face.
+
+      Important conditions:
+      * TBLResultCode.FontNotInitializes is raised if the font AFace is invalid.
+      * TBLResultCode.OutOfMemory is raised if memory allocation failed. }
+    procedure AddFace(const AFace: IBLFontFace);
+
+    { Queries a font face by family name and returns the font face or nil if
+      not found. }
+    function QueryFace(const AName: String): IBLFontFace; overload;
+
+    { Queries a font face by family name and returns the font face or nil if
+      not found.
+
+      The AProperties parameter contains query properties that the query engine
+      will consider when doing the match. The best candidate will be selected
+      based on the following rules:
+      * Style has the highest priority.
+      * Weight has the lowest priority. }
+    function QueryFace(const AName: String;
+      const AProperties: TBLFontQueryProperties): IBLFontFace; overload;
+
+    { Queries all font-faces by family name and returns an array of font faces. }
+    function QueryFacesByFamilyName(const AName: String): TArray<IBLFontFace>;
+
+    { Whether the font manager is a built-in null instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { The number of IBLFontFace instances the font manager holds. }
+    property FaceCount: Integer read GetFaceCount;
+
+    { The number of unique font families the font manager holds. }
+    property FamilyCount: Integer read GetFamilyCount;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLFontManagerCore read GetHandle;
+  end;
+
+type
+  { Implements IBLFontManager }
+  TBLFontManager = class(TInterfacedObject, IBLFontManager)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLFontManagerCore;
+  protected
+    { IBLFontManager }
+    function GetIsNone: Boolean;
+    function GetFaceCount: Integer;
+    function GetFamilyCount: Integer;
+    function GetHandle: PBLFontManagerCore;
+
+    procedure Reset;
+    function Equals(const AOther: IBLFontManager): Boolean; reintroduce; overload;
+    procedure Initialize;
+    function HasFace(const AFace: IBLFontFace): Boolean;
+    procedure AddFace(const AFace: IBLFontFace);
+    function QueryFace(const AName: String): IBLFontFace; overload;
+    function QueryFace(const AName: String;
+      const AProperties: TBLFontQueryProperties): IBLFontFace; overload;
+    function QueryFacesByFamilyName(const AName: String): TArray<IBLFontFace>;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+
+{$ENDREGION 'Font Manager'}
+
+{$REGION 'Pixel Converter'}
+
+{ ============================================================================
+   [BLPixelConverterCreateFlags]
+  ============================================================================ }
+
+type
+  { Flags used by IBLPixelConverter.Initialize. }
+  TBLPixelConverterCreateFlag = (
+    { Specifies that the source palette in TBLFormatInfo doesn't have to be
+      copied by IBLPixelConverter. The caller must ensure that the palette
+      would stay valid until the pixel converter is destroyed. }
+    DontCopyPalette  = 0,
+
+    { Specifies that the source palette in TBLFormatInfo is alterable and
+      the pixel converter can modify it when preparing the conversion. The
+      modification can be irreversible so only use this flag when you are sure
+      that the palette passed to IBLPixelConverter.Initialize won't be needed
+      outside of pixel conversion.
+
+      The flag DontCopyPalette must be set as well, otherwise this flag would be
+      ignored. }
+    AlterablePalette = 1,
+
+    { When there is no built-in conversion between the given pixel formats it's
+      possible to use an intermediate format that is used during conversion. In
+      such case the base pixel converter creates two more converters that are
+      then used internally.
+
+      This option disables such feature - creating a pixel converter would fail
+      with TBLResultCode.NotImplemented error if direct conversion is not
+      possible. }
+    NoMultiStep      = 2);
+  TBLPixelConverterCreateFlags = set of TBLPixelConverterCreateFlag;
+
+{ ============================================================================
+   [BLPixelConverter - Options]
+  ============================================================================ }
+
+type
+  { Pixel conversion options. }
+  TBLPixelConverterOptions = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLPixelConverterOptions;
+    function GetOrigin: TBLPointI; inline;
+    procedure SetOrigin(const AValue: TBLPointI); inline;
+    function GetGap: Integer; inline;
+    procedure SetGap(const AValue: Integer); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    property Origin: TBLPointI read GetOrigin write SetOrigin;
+    property Gap: Integer read GetGap write SetGap;
+  end;
+  PBLPixelConverterOptions = ^TBLPixelConverterOptions;
+
+{ ============================================================================
+   [BLPixelConverter]
+  ============================================================================ }
+
+type
+  { Provides an interface to convert pixels between various pixel formats. The
+    primary purpose of this class is to allow efficient conversion between
+    pixel formats used natively by Blend2D and pixel formats used elsewhere,
+    for example image codecs or native framebuffers.
+
+    Note: A default-initialized converter has a valid conversion function that
+    would return TBLResultCode.NotInitialized if invoked. Use IsInitialized
+    to test whether the pixel converter was properly initialized. }
+  IBLPixelConverter = interface
+  ['{A75AAED4-30E3-4A65-978F-590528AB2DCF}']
+    {$REGION 'Internal Declarations'}
+    function GetIsInitialized: Boolean;
+    function GetHandle: PBLPixelConverterCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    { Initializes a new pixel converter that will convert pixels described by
+      ASrcInfo into pixels described by ADstInfo.
+
+      Use ACreateFlags to further specify the parameters of the conversion.
+
+      Note: Destination and source format information must be valid, otherwise
+      a TBLResultCode.InvalidValue error is raised. }
+    procedure Initialize(const ASrcInfo, ADstInfo: TBLFormatInfo;
+      const ACreateFlags: TBLPixelConverterCreateFlags = []);
+
+    procedure Reset;
+
+    { Assigns the AOther pixel converter into this one. }
+    procedure Assign(const AOther: IBLPixelConverter);
+
+    { Converts a single span of pixels of AWidth. }
+    procedure ConvertSpan(const ASrcData, ADstData: Pointer;
+      const AWidth: Integer); overload;
+    procedure ConvertSpan(const ASrcData, ADstData: Pointer;
+      const AWidth: Integer; const AOptions: TBLPixelConverterOptions); overload;
+
+    { Converts a rectangular area of pixels from source format to destination. }
+    procedure ConvertRect(const ASrcData: Pointer; const ASrcStride: Integer;
+      const ADstData: Pointer; const ADstStride, AWidth, AHeight: Integer); overload;
+    procedure ConvertRect(const ASrcData: Pointer; const ASrcStride: Integer;
+      const ADstData: Pointer; const ADstStride, AWidth, AHeight: Integer;
+      const AOptions: TBLPixelConverterOptions); overload;
+
+    { Returns True if the converter is initialized. }
+    property IsInitialized: Boolean read GetIsInitialized;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLPixelConverterCore read GetHandle;
+  end;
+
+type
+  { Implements IBLPixelConverter }
+  TBLPixelConverter = class(TInterfacedObject, IBLPixelConverter)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLPixelConverterCore;
+  protected
+    { IBLPixelConverter }
+    function GetIsInitialized: Boolean;
+    function GetHandle: PBLPixelConverterCore;
+
+    procedure Initialize(const ASrcInfo, ADstInfo: TBLFormatInfo;
+      const ACreateFlags: TBLPixelConverterCreateFlags = []);
+
+    procedure Reset;
+
+    procedure Assign(const AOther: IBLPixelConverter);
+
+    procedure ConvertSpan(const ASrcData, ADstData: Pointer;
+      const AWidth: Integer); overload;
+    procedure ConvertSpan(const ASrcData, ADstData: Pointer;
+      const AWidth: Integer; const AOptions: TBLPixelConverterOptions); overload;
+
+    procedure ConvertRect(const ASrcData: Pointer; const ASrcStride: Integer;
+      const ADstData: Pointer; const ADstStride, AWidth, AHeight: Integer); overload;
+    procedure ConvertRect(const ASrcData: Pointer; const ASrcStride: Integer;
+      const ADstData: Pointer; const ADstStride, AWidth, AHeight: Integer;
+      const AOptions: TBLPixelConverterOptions); overload;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    { Creates a pixel converter appropriate for the current platform. This is
+      useful for platforms where the display format does not match the internal
+      Blend2D format. For example, on macOS, iOS and Android, the red and blue
+      color channels need to be swapped. On Windows, Blend2D's internal format
+      matches the display format and no conversion is needed.
+
+      On Windows, it returns a converter that doesn't convert, but just copies
+      the data. However, it is more efficient to not use a pixel converter at
+      all on Windows.
+
+      On other platforms, it creates a converter that converts
+      from PRGB to PBGR. }
+    class function CreatePlatformConverter: IBLPixelConverter; static;
+  end;
+
+{$ENDREGION 'Pixel Converter'}
+
+{$REGION 'Style'}
+
+{ ============================================================================
+   [BLStyle - Enums]
+  ============================================================================ }
+
+type
+  { Style type. }
+  TBLStyleType = (
+    { No style, nothing will be paint. }
+    None     = BL_STYLE_TYPE_NONE,
+
+    { Solid color style. }
+    Solid    = BL_STYLE_TYPE_SOLID,
+
+    { Pattern style. }
+    Pattern  = BL_STYLE_TYPE_PATTERN,
+
+    { Gradient style. }
+    Gradient = BL_STYLE_TYPE_GRADIENT);
+
+{$ENDREGION 'Style'}
+
+{$REGION 'Context'}
+
+{ ============================================================================
+   [BLContext - Enums]
+  ============================================================================ }
+
+type
+  { Rendering context type. }
+  TBLContextType = (
+    { No rendering context. }
+    None   = BL_CONTEXT_TYPE_NONE,
+
+    { Dummy rendering context. }
+    Dummy  = BL_CONTEXT_TYPE_DUMMY,
+
+    { Software-accelerated rendering context. }
+    Raster = BL_CONTEXT_TYPE_RASTER);
+
+type
+  { Rendering context hint. }
+  TBLContextHint = (
+    { Rendering quality. }
+    RenderingQuality = BL_CONTEXT_HINT_RENDERING_QUALITY,
+
+    { Gradient quality. }
+    GradientQuality  = BL_CONTEXT_HINT_GRADIENT_QUALITY,
+
+    { Pattern quality. }
+    PatternQuality   = BL_CONTEXT_HINT_PATTERN_QUALITY);
+
+type
+  { Describes a rendering operation type - fill or stroke.
+
+    The rendering context allows to get and set fill & stroke options directly
+    or via "style" functions that take the rendering operation type (OpType)
+    and dispatch the call to the right function. }
+  TBLContextOpType = (
+    { Fill operation type. }
+    Fill   = BL_CONTEXT_OP_TYPE_FILL,
+
+    { Stroke operation type. }
+    Stroke = BL_CONTEXT_OP_TYPE_STROKE);
+
+type
+  { Rendering context flush-flags, use with IBLContext.Flush. }
+  TBLContextFlushFlag = (
+    _Dummy = 0,
+
+    { Flush the command queue and wait for its completion (will block). }
+    Sync = 31);
+  TBLContextFlushFlags = set of TBLContextFlushFlag;
+
+type
+  { Rendering context create-flags. }
+  TBLContextCreateFlag = (
+    { Fallbacks to a synchronous rendering in case that the rendering engine
+      wasn't able to acquire threads. This flag only makes sense when the
+      asynchronous mode was specified by having TBLContextCreateInfo.ThreadCount
+      greater than 0. If the rendering context fails to acquire at least one
+      thread it would fallback to synchronous mode with no worker threads.
+
+      Note: If this flag is specified with TBLContextCreateInfo.ThreadCount = 1
+      it means to immediately fallback to synchronous rendering. It's only
+      practical to use this flag with 2 or more requested threads. }
+    FallbackToSync      = 3,
+
+    { If this flag is specified and asynchronous rendering is enabled then
+      the context would create its own isolated thread-pool, which is useful
+      for debugging purposes.
+
+      Do not use this flag in production as rendering contexts with isolated
+      thread-pool have to create and destroy all threads they use. This flag
+      is only useful for testing, debugging, and isolated benchmarking. }
+    IsolatedThreadPool  = 24,
+
+    { If this flag is specified and JIT pipeline generation enabled then the
+      rendering context would create its own isolated JIT runtime. which is
+      useful for debugging purposes. This flag will be ignored if JIT pipeline
+      generation is either not supported or was disabled by other flags.
+
+      Do not use this flag in production as rendering contexts with isolated
+      JIT runtime do not use global pipeline cache, that's it, after the
+      rendering context is destroyed the JIT runtime is destroyed with it with
+      all compiled pipelines. This flag is only useful for testing, debugging,
+      and isolated benchmarking. }
+    IsolatedJit         = 25,
+
+    { Override CPU features when creating isolated context. }
+    OverrideCpuFeatures = 26);
+  TBLContextCreateFlags = set of TBLContextCreateFlag;
+
+type
+  { Specifies a rendering context property that can be specific to the rendering
+    context implementation and that doesn't have its own C and C++ API.
+    Different rendering context implementations may expose various properties
+    that users can query to get more details about the rendering context itself,
+    rendering details (like optimizations or possibly limitations), memory
+    details, and other information that was collected during the rendering.
+
+    Properties are never part of the rendering context state - they are
+    stateless and are not subject to Save and Restore. Many properties are
+    purely informative, but some not, e.g. AccumulatedErrorFlags. }
+  TBLContextProperty = (
+    { Number of threads that the rendering context uses for rendering. }
+    ThreadCount           = BL_CONTEXT_PROPERTY_THREAD_COUNT,
+
+    { Accumulated errors collected during the lifetime of the rendering
+      context. }
+    AccumulatedErrorFlags = BL_CONTEXT_PROPERTY_ACCUMULATED_ERROR_FLAGS);
+
+type
+  { Error flags that are accumulated during the rendering context lifetime and
+    that can be queried through TBLContext.QueryAccumulatedErrorFlags. The
+    reason why these flags exist is that errors can happen during asynchronous
+    rendering, and there is no way the user can catch these errors. }
+  TBLContextErrorFlag = (
+    { The rendering context returned or encountered TBLResultCode.InvalidValue,
+      which is mostly related to function argument handling. It's very likely
+      some argument was wrong when calling TBLContext API. }
+    InvalidValue        = 0,
+
+    { Invalid state describes something wrong, for example pipeline compilation
+      problem. }
+    InvalidState        = 1,
+
+    { The rendering context has encountered invalid geometry. }
+    InvalidGeometry     = 2,
+
+    { The rendering context has encountered invalid glyph. }
+    InvalidGlyph        = 3,
+
+    { The rendering context has encountered invalid or uninitialized font. }
+    InvalidFont         = 4,
+
+    { Thread pool was exhausted and couldn't acquire the requested number of
+      threads. }
+    ThreadPoolExhausted = 29,
+
+    { Out of memory condition. }
+    OutOfMemory         = 30,
+
+    { Unknown error, which we don't have flag for. }
+    UnknownError        = 31);
+  TBLContextErrorFlags = set of TBLContextErrorFlag;
+
+type
+  { Clip mode. }
+  TBLClipMode = (
+    { Clipping to a rectangle that is aligned to the pixel grid. }
+    AlignedRect   = BL_CLIP_MODE_ALIGNED_RECT,
+
+    { Clipping to a rectangle that is not aligned to pixel grid. }
+    UnalignedRect = BL_CLIP_MODE_UNALIGNED_RECT,
+
+    { Clipping to a non-rectangular area that is defined by using mask. }
+    Mask          = BL_CLIP_MODE_MASK);
+
+type
+  { Composition & blending operator. }
+  TBLCompOp = (
+    { Source-over [default]. }
+    SrcOver     = BL_COMP_OP_SRC_OVER,
+
+    { Source-copy. }
+    SrcCopy     = BL_COMP_OP_SRC_COPY,
+
+    { Source-in. }
+    SrcIn       = BL_COMP_OP_SRC_IN,
+
+    { Source-out. }
+    SrcOut      = BL_COMP_OP_SRC_OUT,
+
+    { Source-atop. }
+    SrcAtop     = BL_COMP_OP_SRC_ATOP,
+
+    { Destination-over. }
+    DstOver     = BL_COMP_OP_DST_OVER,
+
+    { Destination-copy [nop]. }
+    DstCopy     = BL_COMP_OP_DST_COPY,
+
+    { Destination-in. }
+    DstIn       = BL_COMP_OP_DST_IN,
+
+    { Destination-out. }
+    DstOut      = BL_COMP_OP_DST_OUT,
+
+    { Destination-atop. }
+    DstAtop     = BL_COMP_OP_DST_ATOP,
+
+    { Xor. }
+    ExclusiveOr = BL_COMP_OP_XOR,
+
+    { Clear. }
+    Clear       = BL_COMP_OP_CLEAR,
+
+    { Plus. }
+    Plus        = BL_COMP_OP_PLUS,
+
+    { Minus. }
+    Minus       = BL_COMP_OP_MINUS,
+
+    { Modulate. }
+    Modulate    = BL_COMP_OP_MODULATE,
+
+    { Multiply. }
+    Multiply    = BL_COMP_OP_MULTIPLY,
+
+    { Screen. }
+    Screen      = BL_COMP_OP_SCREEN,
+
+    { Overlay. }
+    Overlay     = BL_COMP_OP_OVERLAY,
+
+    { Darken. }
+    Darken      = BL_COMP_OP_DARKEN,
+
+    { Lighten. }
+    Lighten     = BL_COMP_OP_LIGHTEN,
+
+    { Color dodge. }
+    ColorDodge  = BL_COMP_OP_COLOR_DODGE,
+
+    { Color burn. }
+    ColorBurn   = BL_COMP_OP_COLOR_BURN,
+
+    { Linear burn. }
+    LinearBurn  = BL_COMP_OP_LINEAR_BURN,
+
+    { Linear light. }
+    LinearLight = BL_COMP_OP_LINEAR_LIGHT,
+
+    { Pin light. }
+    PinLight    = BL_COMP_OP_PIN_LIGHT,
+
+    { Hard-light. }
+    HardLight   = BL_COMP_OP_HARD_LIGHT,
+
+    { Soft-light. }
+    SoftLight   = BL_COMP_OP_SOFT_LIGHT,
+
+    { Difference. }
+    Difference  = BL_COMP_OP_DIFFERENCE,
+
+    { Exclusion. }
+    Exclusion   = BL_COMP_OP_EXCLUSION);
+
+type
+  { Gradient rendering quality. }
+  TBLGradientQuality = (
+    { Nearest neighbor. }
+    Nearest = BL_GRADIENT_QUALITY_NEAREST);
+
+type
+  { Pattern quality. }
+  TBLPatternQuality = (
+    { Nearest neighbor. }
+    Nearest  = BL_PATTERN_QUALITY_NEAREST,
+
+    { Bilinear. }
+    Bilinear = BL_PATTERN_QUALITY_BILINEAR);
+
+type
+  { Rendering quality. }
+  TBLRenderingQuality = (
+    { Render using anti-aliasing. }
+    AntiAlias = BL_RENDERING_QUALITY_ANTIALIAS);
+
+{ ============================================================================
+   [BLContext - CreateInfo]
+  ============================================================================ }
+
+type
+  { Information that can be used to customize the rendering context. }
+  TBLContextCreateInfo = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLContextCreateInfo;
+    function GetFlags: TBLContextCreateFlags; inline;
+    procedure SetFlags(const AValue: TBLContextCreateFlags); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    procedure Reset; inline;
+
+    { Create flags, see TBLContextCreateFlags. }
+    property Flags: TBLContextCreateFlags read GetFlags write SetFlags;
+
+    { Number of worker threads to use for asynchronous rendering, if non-zero.
+
+      If ThreadCount is zero it means to initialize the context for synchronous
+      rendering. This means that every operation will take effect immediately.
+      If ThreadCount is 1 it means that the rendering will be asynchronous, but
+      no thread would be acquired from a thread-pool, because the user thread
+      will be used as a worker. And finally, if ThreadCount is greater than 1
+      then total of ThreadCount - 1 threads will be acquired from thread-pool
+      and used as additional workers. }
+    property ThreadCount: Integer read FHandle.threadCount write FHandle.threadCount;
+
+    { CPU features to use in isolated JIT runtime (if supported), only used
+      when Flags contains TBLContextCreateFlag.OverrideCpuFeatures. }
+    property CpuFeatures: Cardinal read FHandle.cpuFeatures write FHandle.cpuFeatures;
+
+    { Maximum number of commands to be queued.
+
+      If this parameter is zero the queue size will be determined automatically.
+
+      TODO: To be documented, has no effect at the moment. }
+    property CommandQueueLimit: Integer read FHandle.commandQueueLimit write FHandle.commandQueueLimit;
+  end;
+  PBLContextCreateInfo = ^TBLContextCreateInfo;
+
+{ ============================================================================
+   [BLContext - Cookie]
+  ============================================================================ }
+
+type
+  { Holds an arbitrary 128-bit value (cookie) that can be used to match other
+    cookies. Blend2D uses cookies in places where it allows to "lock" some
+    state that can only be unlocked by a matching cookie. Please don't confuse
+    cookies with a security of any kind, it's just an arbitrary data that must
+    match to proceed with a certain operation.
+
+    Cookies can be used with IBLContext.Save and IBLContextRestore operations. }
+  TBLContextCookie = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLContextCookie;
+    function GetIsEmpty: Boolean; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    class operator Equal(const ALeft, ARight: TBLContextCookie): Boolean; inline; static;
+    class operator NotEqual(const ALeft, ARight: TBLContextCookie): Boolean; inline; static;
+  public
+    procedure Reset; overload; inline;
+    procedure Reset(const AOther: TBLContextCookie); overload; inline;
+    procedure Reset(const AData0, AData1: UInt64); overload; inline;
+
+    function Equals(const AOther: TBLContextCookie): Boolean; inline;
+
+    property IsEmpty: Boolean read GetIsEmpty;
+  end;
+  PBLContextCookie = ^TBLContextCookie;
+
+{ ============================================================================
+   [BLContext - Hints]
+  ============================================================================ }
+
+type
+  { Rendering context hints. }
+  TBLContextHints = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLContextHints;
+    function GetGradientQuality: TBLGradientQuality; inline;
+    function GetPatternQuality: TBLPatternQuality; inline;
+    function GetRenderingQuality: TBLRenderingQuality; inline;
+    procedure SetGradientQuality(const AValue: TBLGradientQuality); inline;
+    procedure SetPatternQuality(const AValue: TBLPatternQuality); inline;
+    procedure SetRenderingQuality(const AValue: TBLRenderingQuality); inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    property RenderingQuality: TBLRenderingQuality read GetRenderingQuality write SetRenderingQuality;
+    property GradientQuality: TBLGradientQuality read GetGradientQuality write SetGradientQuality;
+    property PatternQuality: TBLPatternQuality read GetPatternQuality write SetPatternQuality;
+  end;
+  PBLContextHints = ^TBLContextHints;
+
+{ ============================================================================
+   [BLContext - State]
+  ============================================================================ }
+
+type
+  { Rendering context state.
+
+    This state is not meant to be created by users, it's only provided for users
+    that want to introspect the rendering context state. }
+  TBLContextState = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLContextState;
+    function GetApproximationOptions: TBLApproximationOptions; inline;
+    function GetCompOp: TBLCompOp; inline;
+    function GetFillRule: TBLFillRule; inline;
+    function GetFillStyle: TBLStyleType; overload; inline;
+    function GetHints: TBLContextHints; inline;
+    function GetMetaMatrix: TBLMatrix2D; inline;
+    function GetSavedStateCount: Integer; inline;
+    function GetStrokeOptions: TBLStrokeOptions; inline;
+    function GetStrokeStyle: TBLStyleType; overload; inline;
+    function GetTargetImage: IBLImage; inline;
+    function GetTargetSize: TBLSize; inline;
+    function GetUserMatrix: TBLMatrix2D; inline;
+    function GetFillAlpha: Double; inline;
+    function GetStrokeAlpha: Double; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    { Target image or image object with nil impl in case that the rendering
+      context doesn't render to an image. }
+    property TargetImage: IBLImage read GetTargetImage;
+
+    { Current size of the target in abstract units, pixels if rendering to
+      IBLImage. }
+    property TargetSize: TBLSize read GetTargetSize;
+
+    { Current context hints. }
+    property Hints: TBLContextHints read GetHints;
+
+    { Current composition operator. }
+    property CompOp: TBLCompOp read GetCompOp;
+
+    { Current fill rule. }
+    property FillRule: TBLFillRule read GetFillRule;
+
+    { Current type of a style for fill operations. }
+    property FillStyle: TBLStyleType read GetFillStyle;
+
+    { Current type of a style for stroke operations. }
+    property StrokeStyle: TBLStyleType read GetStrokeStyle;
+
+    { Approximation options. }
+    property ApproximationOptions: TBLApproximationOptions read GetApproximationOptions;
+
+    { Current global alpha value [0, 1]. }
+    property GlobalAlpha: Double read FHandle.globalAlpha;
+
+    { Current fill alpha }
+    property FillAlpha: Double read GetFillAlpha;
+
+    { Current stroke alpha }
+    property StrokeAlpha: Double read GetStrokeAlpha;
+
+    { Current stroke options. }
+    property StrokeOptions: TBLStrokeOptions read GetStrokeOptions;
+
+    { Current meta transformation matrix. }
+    property MetaMatrix: TBLMatrix2D read GetMetaMatrix;
+
+    { Current user transformation matrix. }
+    property UserMatrix: TBLMatrix2D read GetUserMatrix;
+
+    { Count of saved states in the context. }
+    property SavedStateCount: Integer read GetSavedStateCount;
+  end;
+  PBLContextState = ^TBLContextState;
+
+{ ============================================================================
+   [BLContext]
+  ============================================================================ }
+
+type
+  { Rendering context }
+  IBLContext = interface
+  ['{079F0FF5-12D6-4D53-B5AA-79C1AEE83068}']
+    {$REGION 'Internal Declarations'}
+    function GetTargetSize: TBLSize;
+    function GetTargetWidth: Double;
+    function GetTargetHeight: Double;
+    function GetTargetImage: IBLImage;
+    function GetContextType: TBLContextType;
+    function GetIsNone: Boolean;
+    function GetSavedStateCount: Integer;
+    function GetMetaMatrix: TBLMatrix2D;
+    function GetUserMatrix: TBLMatrix2D;
+    procedure SetUserMatrix(const AValue: TBLMatrix2D);
+    function GetHints: TBLContextHints;
+    procedure SetHints(const AValue: TBLContextHints);
+    function GetRenderingQuality: TBLRenderingQuality;
+    procedure SetRenderingQuality(const AValue: TBLRenderingQuality);
+    function GetGradientQuality: TBLGradientQuality;
+    procedure SetGradientQuality(const AValue: TBLGradientQuality);
+    function GetPatternQuality: TBLPatternQuality;
+    procedure SetPatternQuality(const AValue: TBLPatternQuality);
+    function GetApproximationOptions: TBLApproximationOptions;
+    function GetFlattenMode: TBLFlattenMode;
+    procedure SetFlattenMode(const AValue: TBLFlattenMode);
+    function GetFlattenTolerance: Double;
+    procedure SetFlattenTolerance(const AValue: Double);
+    function GetCompOp: TBLCompOp;
+    procedure SetCompOp(const AValue: TBLCompOp);
+    function GetGlobalAlpha: Double;
+    procedure SetGlobalAlpha(const AValue: Double);
+    function GetFillStyle: TBLStyleType; overload;
+    function GetStrokeStyle: TBLStyleType; overload;
+    function GetFillAlpha: Double;
+    procedure SetFillAlpha(const AValue: Double);
+    function GetStrokeAlpha: Double;
+    procedure SetStrokeAlpha(const AValue: Double);
+    function GetFillColor: TBLRgba32;
+    procedure SetFillColor(const AValue: TBLRgba32);
+    function GetFillColor64: TBLRgba64;
+    procedure SetFillColor64(const AValue: TBLRgba64);
+    function GetFillColorF: TBLRgba;
+    procedure SetFillColorF(const AValue: TBLRgba);
+    function GetStrokeColor: TBLRgba32;
+    procedure SetStrokeColor(const AValue: TBLRgba32);
+    function GetStrokeColor64: TBLRgba64;
+    procedure SetStrokeColor64(const AValue: TBLRgba64);
+    function GetStrokeColorF: TBLRgba;
+    procedure SetStrokeColorF(const AValue: TBLRgba);
+    function GetFillPattern: IBLPattern;
+    procedure SetFillPattern(const AValue: IBLPattern);
+    function GetStrokePattern: IBLPattern;
+    procedure SetStrokePattern(const AValue: IBLPattern);
+    function GetFillGradient: IBLGradient;
+    procedure SetFillGradient(const AValue: IBLGradient);
+    function GetStrokeGradient: IBLGradient;
+    procedure SetStrokeGradient(const AValue: IBLGradient);
+    function GetFillRule: TBLFillRule;
+    procedure SetFillRule(const AValue: TBLFillRule);
+    function GetStrokeWidth: Double;
+    procedure SetStrokeWidth(const AValue: Double);
+    function GetStrokeMiterLimit: Double;
+    procedure SetStrokeMiterLimit(const AValue: Double);
+    function GetStrokeJoin: TBLStrokeJoin;
+    procedure SetStrokeJoin(const AValue: TBLStrokeJoin);
+    function GetStrokeStartCap: TBLStrokeCap;
+    procedure SetStrokeStartCap(const AValue: TBLStrokeCap);
+    function GetStrokeEndCap: TBLStrokeCap;
+    procedure SetStrokeEndCap(const AValue: TBLStrokeCap);
+    function GetStrokeDashOffset: Double;
+    procedure SetStrokeDashOffset(const AValue: Double);
+    function GetStrokeDashArray: TArray<Double>;
+    procedure SetStrokeDashArray(const AValue: TArray<Double>);
+    function GetStrokeTransformOrder: TBLStrokeTransformOrder;
+    procedure SetStrokeTransformOrder(const AValue: TBLStrokeTransformOrder);
+    function GetStrokeOptions: TBLStrokeOptions;
+    procedure SetStrokeOptions(const AValue: TBLStrokeOptions);
+    function GetHandle: PBLContextCore;
+    {$ENDREGION 'Internal Declarations'}
+
+    { Resets this rendering context to the default constructed one.
+
+      Similar behavior to the destructor, but the context will still be valid
+      after Reset and would behave like a default constructed context. }
+    procedure Reset;
+
+    { Whether this and AOther point to the same rendering context. }
+    function Equals(const AOther: IBLContext): Boolean; overload;
+
+    { Starts rendering to the given AImage.
+
+      If this operation succeeds then the rendering context will have exclusive
+      access to the image data. This means that no other renderer can use it
+      during rendering. }
+    procedure Start(const AImage: IBLImage); overload;
+    procedure Start(const AImage: IBLImage;
+      const ACreateInfo: TBLContextCreateInfo); overload;
+
+    { Waits for completion of all render commands and detaches the rendering
+      context from the rendering target. After Finish completes the rendering
+      context implementation would be released and replaced by a built-in null
+      instance (no context). }
+    procedure Finish;
+
+    { Flushes the context }
+    procedure Flush(const AFlags: TBLContextFlushFlags);
+
+    { Queries the number of threads that the rendering context uses.
+
+      If the returned value is zero it means that the rendering is synchronous,
+      otherwise it describes the number of threads used for asynchronous
+      rendering which include the user thread. For example if the returned value
+      is 2 it means that the rendering context uses the user thread and one more
+      worker. }
+    function QueryThreadCount: Integer;
+
+    { Queries accumulated errors as flags.
+
+      Errors may accumulate during the lifetime of the rendering context. }
+    function QueryAccumulatedErrorFlags: TBLContextErrorFlags;
+
+    { Saves the current rendering context state.
+
+      Blend2D uses optimizations that make Save a cheap operation. Only core
+      values are actually saved in Save, others will only be saved if they
+      are modified. This means that consecutive calls to Save and Restore
+      do almost nothing. }
+    procedure Save; overload;
+
+    { Saves the current rendering context state and creates a restoration
+      ACookie.
+
+      If you use a ACookie to save a state you have to use the same cookie to
+      restore it otherwise the Restore would fail. Please note that cookies
+      are not a means of security, they are provided for making it easier to
+      guarantee that a code that you may not control won't break your context. }
+    procedure Save(out ACookie: TBLContextCookie); overload;
+
+    { Restores the top-most saved context-state.
+
+      Possible errors:
+      * TBLResultCode.NoStatesToRestore: There are no saved states to restore.
+      * TBLResultCode.NoMatchingCookie: Previous state was saved with cookie,
+        which was not provided. You would need the correct cookie to restore
+        such state. }
+    procedure Restore; overload;
+
+    { Restores to the point that matches the given ACookie.
+
+      More than one state can be restored in case that the ACookie points to
+      some previous state in the list.
+
+      Possible errors:
+      * TBLResultCode.NoStatesToRestore: There are no saved states to restore.
+      * TBLResultCode.NoMatchingCookie: The cookie did't match any saved state. }
+    procedure Restore(const ACookie: TBLContextCookie); overload;
+
+    { Resets user matrix to identity. }
+    procedure ResetMatrix;
+
+    procedure Translate(const AX, AY: Double); overload;
+    procedure Translate(const APoint: TBLPointI); overload;
+    procedure Translate(const APoint: TBLPoint); overload;
+    procedure Scale(const AXY: Double); overload;
+    procedure Scale(const AX, AY: Double); overload;
+    procedure Scale(const APoint: TBLPointI); overload;
+    procedure Scale(const APoint: TBLPoint); overload;
+    procedure Skew(const AX, AY: Double); overload;
+    procedure Skew(const APoint: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double); overload;
+    procedure Rotate(const AAngle, AX, AY: Double); overload;
+    procedure Rotate(const AAngle: Double; const APoint: TBLPointI); overload;
+    procedure Rotate(const AAngle: Double; const APoint: TBLPoint); overload;
+    procedure Transform(const AMatrix: TBLMatrix2D);
+
+    procedure PostTranslate(const AX, AY: Double); overload;
+    procedure PostTranslate(const APoint: TBLPointI); overload;
+    procedure PostTranslate(const APoint: TBLPoint); overload;
+    procedure PostScale(const AXY: Double); overload;
+    procedure PostScale(const AX, AY: Double); overload;
+    procedure PostScale(const APoint: TBLPointI); overload;
+    procedure PostScale(const APoint: TBLPoint); overload;
+    procedure PostSkew(const AX, AY: Double); overload;
+    procedure PostSkew(const APoint: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double); overload;
+    procedure PostRotate(const AAngle, AX, AY: Double); overload;
+    procedure PostRotate(const AAngle: Double; const APoint: TBLPointI); overload;
+    procedure PostRotate(const AAngle: Double; const APoint: TBLPoint); overload;
+    procedure PostTransform(const AMatrix: TBLMatrix2D);
+
+    { Store the result of combining the current MetaMatrix and UserMatrix
+      to MetaMatrix and reset UserMatrix to identity.
+
+      Please note that this operation is irreversible. The only way to restore
+      both matrices to the state before the call to UserToMeta is to use
+      Save and Restore functions. }
+    procedure UserToMeta;
+
+    { These are alternatives to the FillColor, FillColor64, FillPattern and
+      FillGradient properties. }
+    procedure GetFillStyle(out ARgba: TBLRgba32); overload;
+    procedure GetFillStyle(out ARgba: TBLRgba64); overload;
+    procedure GetFillStyle(out ARgba: TBLRgba); overload;
+    procedure GetFillStyle(out APattern: IBLPattern); overload;
+    procedure GetFillStyle(out AGradient: IBLGradient); overload;
+
+    procedure SetFillStyle(const ARgba: TBLRgba32); overload;
+    procedure SetFillStyle(const ARgba: TBLRgba64); overload;
+    procedure SetFillStyle(const ARgba: TBLRgba); overload;
+    procedure SetFillStyle(const APattern: IBLPattern); overload;
+    procedure SetFillStyle(const AGradient: IBLGradient); overload;
+    procedure SetFillStyle(const AImage: IBLImage); overload;
+
+    { These are alternatives to the StrokeColor, StrokeColor64, StrokePattern
+      and StrokeGradient properties. }
+    procedure GetStrokeStyle(out ARgba: TBLRgba32); overload;
+    procedure GetStrokeStyle(out ARgba: TBLRgba64); overload;
+    procedure GetStrokeStyle(out ARgba: TBLRgba); overload;
+    procedure GetStrokeStyle(out APattern: IBLPattern); overload;
+    procedure GetStrokeStyle(out AGradient: IBLGradient); overload;
+
+    procedure SetStrokeStyle(const ARgba: TBLRgba32); overload;
+    procedure SetStrokeStyle(const ARgba: TBLRgba64); overload;
+    procedure SetStrokeStyle(const ARgba: TBLRgba); overload;
+    procedure SetStrokeStyle(const APattern: IBLPattern); overload;
+    procedure SetStrokeStyle(const AGradient: IBLGradient); overload;
+    procedure SetStrokeStyle(const AImage: IBLImage); overload;
+
+    { Restores clipping to the last saved state or to the context default
+      clipping if there is no saved state.
+
+      If there are no saved states then it resets clipping completely to the
+      initial state that was used when the rendering context was created. }
+    procedure RestoreClipping;
+    procedure ClipToRect(const ARect: TBLRectI); overload;
+    procedure ClipToRect(const ARect: TBLRect); overload;
+    procedure ClipToRect(const AX, AY, AW, AH: Double); overload;
+
+    { Clear everything. }
+    procedure ClearAll;
+
+    { Clears a rectangle ARect. }
+    procedure ClearRect(const ARect: TBLRectI); overload;
+    procedure ClearRect(const ARect: TBLRect); overload;
+    procedure ClearRect(const AX, AY, AW, AH: Double); overload;
+
+    { Fills everything. }
+    procedure FillAll;
+
+    { Fills a box. }
+    procedure FillBox(const ABox: TBLBoxI); overload;
+    procedure FillBox(const ABox: TBLBox); overload;
+    procedure FillBox(const AX0, AY0, AX1, AY1: Double); overload;
+
+    { Fills a rectangle ARect. }
+    procedure FillRect(const ARect: TBLRectI); overload;
+    procedure FillRect(const ARect: TBLRect); overload;
+    procedure FillRect(const AX, AY, AW, AH: Double); overload;
+
+    { Fills a circle. }
+    procedure FillCircle(const ACircle: TBLCircle); overload;
+    procedure FillCircle(const ACX, ACY, AR: Double); overload;
+
+    { Fills an ellipse. }
+    procedure FillEllipse(const AEllipse: TBLEllipse); overload;
+    procedure FillEllipse(const ACX, ACY, ARX, ARY: Double); overload;
+
+    { Fills a rounded rectangle. }
+    procedure FillRoundRect(const ARoundRect: TBLRoundRect); overload;
+    procedure FillRoundRect(const ARect: TBLRect; const AR: Double); overload;
+    procedure FillRoundRect(const ARect: TBLRect; const ARX, ARY: Double); overload;
+    procedure FillRoundRect(const AX, AY, AW, AH, AR: Double); overload;
+    procedure FillRoundRect(const AX, AY, AW, AH, ARX, ARY: Double); overload;
+
+    { Fills a chord. }
+    procedure FillChord(const AChord: TBLArc); overload;
+    procedure FillChord(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure FillChord(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    { Fills a pie. }
+    procedure FillPie(const APie: TBLArc); overload;
+    procedure FillPie(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure FillPie(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    { Fills a triangle. }
+    procedure FillTriangle(const ATriangle: TBLTriangle); overload;
+    procedure FillTriangle(const AX0, AY0, AX1, AY1, AX2, AY2: Double); overload;
+
+    { Fills a polygon. }
+    procedure FillPolygon(const APoly: TArray<TBLPoint>); overload;
+    procedure FillPolygon(const APoly: TBLArrayView<TBLPoint>); overload;
+    procedure FillPolygon(const APoly: PBLPoint; const ACount: Integer); overload;
+    procedure FillPolygon(const APoly: TArray<TBLPointI>); overload;
+    procedure FillPolygon(const APoly: TBLArrayView<TBLPointI>); overload;
+    procedure FillPolygon(const APoly: PBLPointI; const ACount: Integer); overload;
+
+    { Fills an array of boxes. }
+    procedure FillBoxArray(const ABoxes: TArray<TBLBox>); overload;
+    procedure FillBoxArray(const ABoxes: TBLArrayView<TBLBox>); overload;
+    procedure FillBoxArray(const ABoxes: PBLBox; const ACount: Integer); overload;
+    procedure FillBoxArray(const ABoxes: TArray<TBLBoxI>); overload;
+    procedure FillBoxArray(const ABoxes: TBLArrayView<TBLBoxI>); overload;
+    procedure FillBoxArray(const ABoxes: PBLBoxI; const ACount: Integer); overload;
+
+    { Fills an array of rectangles. }
+    procedure FillRectArray(const ARects: TArray<TBLRect>); overload;
+    procedure FillRectArray(const ARects: TBLArrayView<TBLRect>); overload;
+    procedure FillRectArray(const ARects: PBLRect; const ACount: Integer); overload;
+    procedure FillRectArray(const ARects: TArray<TBLRectI>); overload;
+    procedure FillRectArray(const ARects: TBLArrayView<TBLRectI>); overload;
+    procedure FillRectArray(const ARects: PBLRectI; const ACount: Integer); overload;
+
+    { Fills the given ARegion. }
+    procedure FillRegion(const ARegion: IBLRegion);
+
+    { Fills the given Path. }
+    procedure FillPath(const APath: IBLPath);
+
+    { Fills the passed text by using the given AFont. }
+    procedure FillText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: String); overload;
+    procedure FillText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: String); overload;
+    procedure FillText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: UTF8String); overload;
+    procedure FillText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: UTF8String); overload;
+    procedure FillText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: UCS4String); overload;
+    procedure FillText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: UCS4String); overload;
+
+    { Fills the passed AGlyphRun by using the given AFont. }
+    procedure FillGlyphRun(const ADst: TBLPointI; const AFont: IBLFont;
+      const AGlyphRun: TBLGlyphRun); overload;
+    procedure FillGlyphRun(const ADst: TBLPoint; const AFont: IBLFont;
+      const AGlyphRun: TBLGlyphRun); overload;
+    procedure FillGlyphRun(const ADst: TBLPointI; const AFont: IBLFont;
+      const AGlyphRun: PBLGlyphRun); overload;
+    procedure FillGlyphRun(const ADst: TBLPoint; const AFont: IBLFont;
+      const AGlyphRun: PBLGlyphRun); overload;
+
+    { Strokes a box. }
+    procedure StrokeBox(const ABox: TBLBoxI); overload;
+    procedure StrokeBox(const ABox: TBLBox); overload;
+    procedure StrokeBox(const AX0, AY0, AX1, AY1: Double); overload;
+
+    { Strokes a rectangle. }
+    procedure StrokeRect(const ARect: TBLRectI); overload;
+    procedure StrokeRect(const ARect: TBLRect); overload;
+    procedure StrokeRect(const AX, AY, AW, AH: Double); overload;
+
+    { Strokes a line. }
+    procedure StrokeLine(const ALine: TBLLine); overload;
+    procedure StrokeLine(const AP0, AP1: TBLPoint); overload;
+    procedure StrokeLine(const AX0, AY0, AX1, AY1: Double); overload;
+
+    { Strokes a circle. }
+    procedure StrokeCircle(const ACircle: TBLCircle); overload;
+    procedure StrokeCircle(const ACX, ACY, AR: Double); overload;
+
+    { Strokes an ellipse. }
+    procedure StrokeEllipse(const AEllipse: TBLEllipse); overload;
+    procedure StrokeEllipse(const ACX, ACY, ARX, ARY: Double); overload;
+
+    { Strokes a rounded rectangle. }
+    procedure StrokeRoundRect(const ARoundRect: TBLRoundRect); overload;
+    procedure StrokeRoundRect(const ARect: TBLRect; const AR: Double); overload;
+    procedure StrokeRoundRect(const ARect: TBLRect; const ARX, ARY: Double); overload;
+    procedure StrokeRoundRect(const AX, AY, AW, AH, AR: Double); overload;
+    procedure StrokeRoundRect(const AX, AY, AW, AH, ARX, ARY: Double); overload;
+
+    { Strokes an arc. }
+    procedure StrokeArc(const AArc: TBLArc); overload;
+    procedure StrokeArc(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure StrokeArc(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    { Strokes a chord. }
+    procedure StrokeChord(const AChord: TBLArc); overload;
+    procedure StrokeChord(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure StrokeChord(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    { Strokes a pie. }
+    procedure StrokePie(const APie: TBLArc); overload;
+    procedure StrokePie(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure StrokePie(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    { Strokes a triangle. }
+    procedure StrokeTriangle(const ATriangle: TBLTriangle); overload;
+    procedure StrokeTriangle(const AX0, AY0, AX1, AY1, AX2, AY2: Double); overload;
+
+    { Strokes a polyline. }
+    procedure StrokePolyline(const APoly: TArray<TBLPoint>); overload;
+    procedure StrokePolyline(const APoly: TBLArrayView<TBLPoint>); overload;
+    procedure StrokePolyline(const APoly: PBLPoint; const ACount: Integer); overload;
+    procedure StrokePolyline(const APoly: TArray<TBLPointI>); overload;
+    procedure StrokePolyline(const APoly: TBLArrayView<TBLPointI>); overload;
+    procedure StrokePolyline(const APoly: PBLPointI; const ACount: Integer); overload;
+
+    { Strokes a polygon. }
+    procedure StrokePolygon(const APoly: TArray<TBLPoint>); overload;
+    procedure StrokePolygon(const APoly: TBLArrayView<TBLPoint>); overload;
+    procedure StrokePolygon(const APoly: PBLPoint; const ACount: Integer); overload;
+    procedure StrokePolygon(const APoly: TArray<TBLPointI>); overload;
+    procedure StrokePolygon(const APoly: TBLArrayView<TBLPointI>); overload;
+    procedure StrokePolygon(const APoly: PBLPointI; const ACount: Integer); overload;
+
+    { Strokes an array of boxes. }
+    procedure StrokeBoxArray(const ABoxes: TArray<TBLBox>); overload;
+    procedure StrokeBoxArray(const ABoxes: TBLArrayView<TBLBox>); overload;
+    procedure StrokeBoxArray(const ABoxes: PBLBox; const ACount: Integer); overload;
+    procedure StrokeBoxArray(const ABoxes: TArray<TBLBoxI>); overload;
+    procedure StrokeBoxArray(const ABoxes: TBLArrayView<TBLBoxI>); overload;
+    procedure StrokeBoxArray(const ABoxes: PBLBoxI; const ACount: Integer); overload;
+
+    { Strokes an array of rectangles. }
+    procedure StrokeRectArray(const ARects: TArray<TBLRect>); overload;
+    procedure StrokeRectArray(const ARects: TBLArrayView<TBLRect>); overload;
+    procedure StrokeRectArray(const ARects: PBLRect; const ACount: Integer); overload;
+    procedure StrokeRectArray(const ARects: TArray<TBLRectI>); overload;
+    procedure StrokeRectArray(const ARects: TBLArrayView<TBLRectI>); overload;
+    procedure StrokeRectArray(const ARects: PBLRectI; const ACount: Integer); overload;
+
+    { Strokes the given Path. }
+    procedure StrokePath(const APath: IBLPath);
+
+    { Strokes the passed text by using the given AFont. }
+    procedure StrokeText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: String); overload;
+    procedure StrokeText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: String); overload;
+    procedure StrokeText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: UTF8String); overload;
+    procedure StrokeText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: UTF8String); overload;
+    procedure StrokeText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: UCS4String); overload;
+    procedure StrokeText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: UCS4String); overload;
+
+    { Strokes the passed AGlyphRun by using the given AFont. }
+    procedure StrokeGlyphRun(const ADst: TBLPointI; const AFont: IBLFont;
+      const AGlyphRun: TBLGlyphRun); overload;
+    procedure StrokeGlyphRun(const ADst: TBLPoint; const AFont: IBLFont;
+      const AGlyphRun: TBLGlyphRun); overload;
+
+    { Blits source image ASrc at coordinates specified by ADst. }
+    procedure BlitImage(const ADst: TBLPoint; const ASrc: IBLImage); overload;
+    procedure BlitImage(const ADst: TBLPointI; const ASrc: IBLImage); overload;
+
+    { Blits an area of source image ASrc specified by ASrcArea at coordinates
+      specified by ADst.}
+    procedure BlitImage(const ADst: TBLPoint; const ASrc: IBLImage;
+      const ASrcArea: TBLRectI); overload;
+    procedure BlitImage(const ADst: TBLPointI; const ASrc: IBLImage;
+      const ASrcArea: TBLRectI); overload;
+
+    { Blits a source image ASrc scaled to fit into ADst rectangle. }
+    procedure BlitImage(const ADst: TBLRect; const ASrc: IBLImage); overload;
+    procedure BlitImage(const ADst: TBLRectI; const ASrc: IBLImage); overload;
+
+    { Blits an area of source image ASrc specified by ASrcArea scaled to fit
+      into ADst rectangle. }
+    procedure BlitImage(const ADst: TBLRect; const ASrc: IBLImage;
+      const ASrcArea: TBLRectI); overload;
+    procedure BlitImage(const ADst: TBLRectI; const ASrc: IBLImage;
+      const ASrcArea: TBLRectI); overload;
+
+    { Target size in abstract units (pixels in case of IBLImage) }
+    property TargetSize: TBLSize read GetTargetSize;
+
+    { Target width in abstract units (pixels in case of IBLImage) }
+    property TargetWidth: Double read GetTargetWidth;
+
+    { Target width in abstract units (pixels in case of IBLImage) }
+    property TargetHeight: Double read GetTargetHeight;
+
+    { Returns the target image or nil if there is no target image.
+
+      Note: The rendering context doesn't own the image, but it increases its
+      writer count, which means that the image will not be destroyed even when
+      user destroys it during the rendering (in such case it will be destroyed
+      after the rendering ends when the writer count goes to zero). This means
+      that the rendering context must hold the image and not the pointer to
+      the IBLImage passed to either the constructor or Start function. So the
+      returned pointer is not the same as the pointer passed to Start, but it
+      points to the same impl. }
+    property TargetImage: IBLImage read GetTargetImage;
+
+    { The type of this context }
+    property ContextType: TBLContextType read GetContextType;
+
+    { Whether the context is a built-in null instance. }
+    property IsNone: Boolean read GetIsNone;
+
+    { The number of saved states in the context (0 means no saved states). }
+    property SavedStateCount: Integer read GetSavedStateCount;
+
+    { Meta-matrix.
+
+      Meta matrix is a core transformation matrix that is normally not changed
+      by transformations applied to the context. Instead it acts as a secondary
+      matrix used to create the final transformation matrix from meta and user
+      matrices.
+
+      Meta matrix can be used to scale the whole context for HI-DPI rendering
+      or to change the orientation of the image being rendered, however, the
+      number of use-cases is unlimited.
+
+      To change the meta-matrix you must first change user-matrix and then call
+      UserToMeta, which would update meta-matrix and clear user-matrix.
+
+      See UserMatrix and UserToMeta. }
+    property MetaMatrix: TBLMatrix2D read GetMetaMatrix;
+
+    { User-matrix.
+
+      User matrix contains all transformations that happened to the rendering
+      context unless the context was restored or UserToMeta was called. }
+    property UserMatrix: TBLMatrix2D read GetUserMatrix write SetUserMatrix;
+
+    { Rendering hints. }
+    property Hints: TBLContextHints read GetHints write SetHints;
+    property RenderingQuality: TBLRenderingQuality read GetRenderingQuality write SetRenderingQuality;
+    property GradientQuality: TBLGradientQuality read GetGradientQuality write SetGradientQuality;
+    property PatternQuality: TBLPatternQuality read GetPatternQuality write SetPatternQuality;
+
+    { Approximation options. }
+    property ApproximationOptions: TBLApproximationOptions read GetApproximationOptions;
+
+    { Flatten mode. }
+    property FlattenMode: TBLFlattenMode read GetFlattenMode write SetFlattenMode;
+
+    { Tolerance used for curve flattening. }
+    property FlattenTolerance: Double read GetFlattenTolerance write SetFlattenTolerance;
+
+    { Composition operator. }
+    property CompOp: TBLCompOp read GetCompOp write SetCompOp;
+
+    { Global alpha value. }
+    property GlobalAlpha: Double read GetGlobalAlpha write SetGlobalAlpha;
+
+    { Fill style }
+    property FillStyle: TBLStyleType read GetFillStyle;
+
+    { Stroke style }
+    property StrokeStyle: TBLStyleType read GetStrokeStyle;
+
+    { Fill alpha }
+    property FillAlpha: Double read GetFillAlpha write SetFillAlpha;
+
+    { Stroke alpha }
+    property StrokeAlpha: Double read GetStrokeAlpha write SetStrokeAlpha;
+
+    { Fill color }
+    property FillColor: TBLRgba32 read GetFillColor write SetFillColor;
+    property FillColor64: TBLRgba64 read GetFillColor64 write SetFillColor64;
+    property FillColorF: TBLRgba read GetFillColorF write SetFillColorF;
+
+    { Stroke color }
+    property StrokeColor: TBLRgba32 read GetStrokeColor write SetStrokeColor;
+    property StrokeColor64: TBLRgba64 read GetStrokeColor64 write SetStrokeColor64;
+    property StrokeColorF: TBLRgba read GetStrokeColorF write SetStrokeColorF;
+
+    { Fill Pattern }
+    property FillPattern: IBLPattern read GetFillPattern write SetFillPattern;
+
+    { Stroke Pattern }
+    property StrokePattern: IBLPattern read GetStrokePattern write SetStrokePattern;
+
+    { Fill Gradient }
+    property FillGradient: IBLGradient read GetFillGradient write SetFillGradient;
+
+    { Stroke Gradient }
+    property StrokeGradient: IBLGradient read GetStrokeGradient write SetStrokeGradient;
+
+    { Fill rule }
+    property FillRule: TBLFillRule read GetFillRule write SetFillRule;
+
+    { Stroke width }
+    property StrokeWidth: Double read GetStrokeWidth write SetStrokeWidth;
+
+    { Stroke miter-limit. }
+    property StrokeMiterLimit: Double read GetStrokeMiterLimit write SetStrokeMiterLimit;
+
+    { Stroke join }
+    property StrokeJoin: TBLStrokeJoin read GetStrokeJoin write SetStrokeJoin;
+
+    { Stroke start-cap }
+    property StrokeStartCap: TBLStrokeCap read GetStrokeStartCap write SetStrokeStartCap;
+
+    { Stroke end-cap }
+    property StrokeEndCap: TBLStrokeCap read GetStrokeEndCap write SetStrokeEndCap;
+
+    { Stroke dash-offset. }
+    property StrokeDashOffset: Double read GetStrokeDashOffset write SetStrokeDashOffset;
+
+    { Stroke dash-array. }
+    property StrokeDashArray: TArray<Double> read GetStrokeDashArray write SetStrokeDashArray;
+
+    { Stroke transform order }
+    property StrokeTransformOrder: TBLStrokeTransformOrder read GetStrokeTransformOrder write SetStrokeTransformOrder;
+
+    { All stroke options }
+    property StrokeOptions: TBLStrokeOptions read GetStrokeOptions write SetStrokeOptions;
+
+    { Internal handle for use with the C API }
+    property Handle: PBLContextCore read GetHandle;
+  end;
+
+type
+  { Implements IBLContext }
+  TBLContext = class(TInterfacedObject, IBLContext)
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLContextCore;
+  protected
+    { IBLContext }
+    function GetTargetSize: TBLSize;
+    function GetTargetWidth: Double;
+    function GetTargetHeight: Double;
+    function GetTargetImage: IBLImage;
+    function GetContextType: TBLContextType;
+    function GetIsNone: Boolean;
+    function GetSavedStateCount: Integer;
+    function GetMetaMatrix: TBLMatrix2D;
+    function GetUserMatrix: TBLMatrix2D;
+    procedure SetUserMatrix(const AValue: TBLMatrix2D);
+    function GetHints: TBLContextHints;
+    procedure SetHints(const AValue: TBLContextHints);
+    function GetRenderingQuality: TBLRenderingQuality;
+    procedure SetRenderingQuality(const AValue: TBLRenderingQuality);
+    function GetGradientQuality: TBLGradientQuality;
+    procedure SetGradientQuality(const AValue: TBLGradientQuality);
+    function GetPatternQuality: TBLPatternQuality;
+    procedure SetPatternQuality(const AValue: TBLPatternQuality);
+    function GetApproximationOptions: TBLApproximationOptions;
+    function GetFlattenMode: TBLFlattenMode;
+    procedure SetFlattenMode(const AValue: TBLFlattenMode);
+    function GetFlattenTolerance: Double;
+    procedure SetFlattenTolerance(const AValue: Double);
+    function GetCompOp: TBLCompOp;
+    procedure SetCompOp(const AValue: TBLCompOp);
+    function GetGlobalAlpha: Double;
+    procedure SetGlobalAlpha(const AValue: Double);
+    function GetFillStyle: TBLStyleType; overload;
+    function GetStrokeStyle: TBLStyleType; overload;
+    function GetFillAlpha: Double;
+    procedure SetFillAlpha(const AValue: Double);
+    function GetStrokeAlpha: Double;
+    procedure SetStrokeAlpha(const AValue: Double);
+    function GetFillColor: TBLRgba32;
+    procedure SetFillColor(const AValue: TBLRgba32);
+    function GetFillColor64: TBLRgba64;
+    procedure SetFillColor64(const AValue: TBLRgba64);
+    function GetFillColorF: TBLRgba;
+    procedure SetFillColorF(const AValue: TBLRgba);
+    function GetStrokeColor: TBLRgba32;
+    procedure SetStrokeColor(const AValue: TBLRgba32);
+    function GetStrokeColor64: TBLRgba64;
+    procedure SetStrokeColor64(const AValue: TBLRgba64);
+    function GetStrokeColorF: TBLRgba;
+    procedure SetStrokeColorF(const AValue: TBLRgba);
+    function GetFillPattern: IBLPattern;
+    procedure SetFillPattern(const AValue: IBLPattern);
+    function GetStrokePattern: IBLPattern;
+    procedure SetStrokePattern(const AValue: IBLPattern);
+    function GetFillGradient: IBLGradient;
+    procedure SetFillGradient(const AValue: IBLGradient);
+    function GetStrokeGradient: IBLGradient;
+    procedure SetStrokeGradient(const AValue: IBLGradient);
+    function GetFillRule: TBLFillRule;
+    procedure SetFillRule(const AValue: TBLFillRule);
+    function GetStrokeWidth: Double;
+    procedure SetStrokeWidth(const AValue: Double);
+    function GetStrokeMiterLimit: Double;
+    procedure SetStrokeMiterLimit(const AValue: Double);
+    function GetStrokeJoin: TBLStrokeJoin;
+    procedure SetStrokeJoin(const AValue: TBLStrokeJoin);
+    function GetStrokeStartCap: TBLStrokeCap;
+    procedure SetStrokeStartCap(const AValue: TBLStrokeCap);
+    function GetStrokeEndCap: TBLStrokeCap;
+    procedure SetStrokeEndCap(const AValue: TBLStrokeCap);
+    function GetStrokeDashOffset: Double;
+    procedure SetStrokeDashOffset(const AValue: Double);
+    function GetStrokeDashArray: TArray<Double>;
+    procedure SetStrokeDashArray(const AValue: TArray<Double>);
+    function GetStrokeTransformOrder: TBLStrokeTransformOrder;
+    procedure SetStrokeTransformOrder(const AValue: TBLStrokeTransformOrder);
+    function GetStrokeOptions: TBLStrokeOptions;
+    procedure SetStrokeOptions(const AValue: TBLStrokeOptions);
+    function GetHandle: PBLContextCore;
+
+    procedure Reset;
+    function Equals(const AOther: IBLContext): Boolean; reintroduce; overload;
+
+    procedure Start(const AImage: IBLImage); overload;
+    procedure Start(const AImage: IBLImage;
+      const ACreateInfo: TBLContextCreateInfo); overload;
+    procedure Finish;
+    procedure Flush(const AFlags: TBLContextFlushFlags);
+
+    function QueryThreadCount: Integer;
+    function QueryAccumulatedErrorFlags: TBLContextErrorFlags;
+
+    procedure Save; overload;
+    procedure Save(out ACookie: TBLContextCookie); overload;
+    procedure Restore; overload;
+    procedure Restore(const ACookie: TBLContextCookie); overload;
+
+    procedure ResetMatrix;
+
+    procedure Translate(const AX, AY: Double); overload;
+    procedure Translate(const APoint: TBLPointI); overload;
+    procedure Translate(const APoint: TBLPoint); overload;
+    procedure Scale(const AXY: Double); overload;
+    procedure Scale(const AX, AY: Double); overload;
+    procedure Scale(const APoint: TBLPointI); overload;
+    procedure Scale(const APoint: TBLPoint); overload;
+    procedure Skew(const AX, AY: Double); overload;
+    procedure Skew(const APoint: TBLPoint); overload;
+    procedure Rotate(const AAngle: Double); overload;
+    procedure Rotate(const AAngle, AX, AY: Double); overload;
+    procedure Rotate(const AAngle: Double; const APoint: TBLPointI); overload;
+    procedure Rotate(const AAngle: Double; const APoint: TBLPoint); overload;
+    procedure Transform(const AMatrix: TBLMatrix2D);
+
+    procedure PostTranslate(const AX, AY: Double); overload;
+    procedure PostTranslate(const APoint: TBLPointI); overload;
+    procedure PostTranslate(const APoint: TBLPoint); overload;
+    procedure PostScale(const AXY: Double); overload;
+    procedure PostScale(const AX, AY: Double); overload;
+    procedure PostScale(const APoint: TBLPointI); overload;
+    procedure PostScale(const APoint: TBLPoint); overload;
+    procedure PostSkew(const AX, AY: Double); overload;
+    procedure PostSkew(const APoint: TBLPoint); overload;
+    procedure PostRotate(const AAngle: Double); overload;
+    procedure PostRotate(const AAngle, AX, AY: Double); overload;
+    procedure PostRotate(const AAngle: Double; const APoint: TBLPointI); overload;
+    procedure PostRotate(const AAngle: Double; const APoint: TBLPoint); overload;
+    procedure PostTransform(const AMatrix: TBLMatrix2D);
+
+    procedure UserToMeta;
+
+    procedure GetFillStyle(out ARgba: TBLRgba32); overload;
+    procedure GetFillStyle(out ARgba: TBLRgba64); overload;
+    procedure GetFillStyle(out ARgba: TBLRgba); overload;
+    procedure GetFillStyle(out APattern: IBLPattern); overload;
+    procedure GetFillStyle(out AGradient: IBLGradient); overload;
+
+    procedure SetFillStyle(const ARgba: TBLRgba32); overload;
+    procedure SetFillStyle(const ARgba: TBLRgba64); overload;
+    procedure SetFillStyle(const ARgba: TBLRgba); overload;
+    procedure SetFillStyle(const APattern: IBLPattern); overload;
+    procedure SetFillStyle(const AGradient: IBLGradient); overload;
+    procedure SetFillStyle(const AImage: IBLImage); overload;
+
+    procedure GetStrokeStyle(out ARgba: TBLRgba32); overload;
+    procedure GetStrokeStyle(out ARgba: TBLRgba64); overload;
+    procedure GetStrokeStyle(out ARgba: TBLRgba); overload;
+    procedure GetStrokeStyle(out APattern: IBLPattern); overload;
+    procedure GetStrokeStyle(out AGradient: IBLGradient); overload;
+
+    procedure SetStrokeStyle(const ARgba: TBLRgba32); overload;
+    procedure SetStrokeStyle(const ARgba: TBLRgba64); overload;
+    procedure SetStrokeStyle(const ARgba: TBLRgba); overload;
+    procedure SetStrokeStyle(const APattern: IBLPattern); overload;
+    procedure SetStrokeStyle(const AGradient: IBLGradient); overload;
+    procedure SetStrokeStyle(const AImage: IBLImage); overload;
+
+    procedure RestoreClipping;
+    procedure ClipToRect(const ARect: TBLRectI); overload;
+    procedure ClipToRect(const ARect: TBLRect); overload;
+    procedure ClipToRect(const AX, AY, AW, AH: Double); overload;
+
+    procedure ClearAll;
+    procedure ClearRect(const ARect: TBLRectI); overload;
+    procedure ClearRect(const ARect: TBLRect); overload;
+    procedure ClearRect(const AX, AY, AW, AH: Double); overload;
+
+    procedure FillAll;
+
+    procedure FillBox(const ABox: TBLBoxI); overload;
+    procedure FillBox(const ABox: TBLBox); overload;
+    procedure FillBox(const AX0, AY0, AX1, AY1: Double); overload;
+
+    procedure FillRect(const ARect: TBLRectI); overload;
+    procedure FillRect(const ARect: TBLRect); overload;
+    procedure FillRect(const AX, AY, AW, AH: Double); overload;
+
+    procedure FillCircle(const ACircle: TBLCircle); overload;
+    procedure FillCircle(const ACX, ACY, AR: Double); overload;
+
+    procedure FillEllipse(const AEllipse: TBLEllipse); overload;
+    procedure FillEllipse(const ACX, ACY, ARX, ARY: Double); overload;
+
+    procedure FillRoundRect(const ARoundRect: TBLRoundRect); overload;
+    procedure FillRoundRect(const ARect: TBLRect; const AR: Double); overload;
+    procedure FillRoundRect(const ARect: TBLRect; const ARX, ARY: Double); overload;
+    procedure FillRoundRect(const AX, AY, AW, AH, AR: Double); overload;
+    procedure FillRoundRect(const AX, AY, AW, AH, ARX, ARY: Double); overload;
+
+    procedure FillChord(const AChord: TBLArc); overload;
+    procedure FillChord(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure FillChord(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    procedure FillPie(const APie: TBLArc); overload;
+    procedure FillPie(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure FillPie(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    procedure FillTriangle(const ATriangle: TBLTriangle); overload;
+    procedure FillTriangle(const AX0, AY0, AX1, AY1, AX2, AY2: Double); overload;
+
+    procedure FillPolygon(const APoly: TArray<TBLPoint>); overload;
+    procedure FillPolygon(const APoly: TBLArrayView<TBLPoint>); overload;
+    procedure FillPolygon(const APoly: PBLPoint; const ACount: Integer); overload;
+    procedure FillPolygon(const APoly: TArray<TBLPointI>); overload;
+    procedure FillPolygon(const APoly: TBLArrayView<TBLPointI>); overload;
+    procedure FillPolygon(const APoly: PBLPointI; const ACount: Integer); overload;
+
+    procedure FillBoxArray(const ABoxes: TArray<TBLBox>); overload;
+    procedure FillBoxArray(const ABoxes: TBLArrayView<TBLBox>); overload;
+    procedure FillBoxArray(const ABoxes: PBLBox; const ACount: Integer); overload;
+    procedure FillBoxArray(const ABoxes: TArray<TBLBoxI>); overload;
+    procedure FillBoxArray(const ABoxes: TBLArrayView<TBLBoxI>); overload;
+    procedure FillBoxArray(const ABoxes: PBLBoxI; const ACount: Integer); overload;
+
+    procedure FillRectArray(const ARects: TArray<TBLRect>); overload;
+    procedure FillRectArray(const ARects: TBLArrayView<TBLRect>); overload;
+    procedure FillRectArray(const ARects: PBLRect; const ACount: Integer); overload;
+    procedure FillRectArray(const ARects: TArray<TBLRectI>); overload;
+    procedure FillRectArray(const ARects: TBLArrayView<TBLRectI>); overload;
+    procedure FillRectArray(const ARects: PBLRectI; const ACount: Integer); overload;
+
+    procedure FillRegion(const ARegion: IBLRegion);
+
+    procedure FillPath(const APath: IBLPath);
+
+    procedure FillText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: String); overload;
+    procedure FillText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: String); overload;
+    procedure FillText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: UTF8String); overload;
+    procedure FillText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: UTF8String); overload;
+    procedure FillText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: UCS4String); overload;
+    procedure FillText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: UCS4String); overload;
+
+    procedure FillGlyphRun(const ADst: TBLPointI; const AFont: IBLFont;
+      const AGlyphRun: TBLGlyphRun); overload;
+    procedure FillGlyphRun(const ADst: TBLPoint; const AFont: IBLFont;
+      const AGlyphRun: TBLGlyphRun); overload;
+    procedure FillGlyphRun(const ADst: TBLPointI; const AFont: IBLFont;
+      const AGlyphRun: PBLGlyphRun); overload;
+    procedure FillGlyphRun(const ADst: TBLPoint; const AFont: IBLFont;
+      const AGlyphRun: PBLGlyphRun); overload;
+
+    procedure StrokeBox(const ABox: TBLBoxI); overload;
+    procedure StrokeBox(const ABox: TBLBox); overload;
+    procedure StrokeBox(const AX0, AY0, AX1, AY1: Double); overload;
+
+    procedure StrokeRect(const ARect: TBLRectI); overload;
+    procedure StrokeRect(const ARect: TBLRect); overload;
+    procedure StrokeRect(const AX, AY, AW, AH: Double); overload;
+
+    procedure StrokeLine(const ALine: TBLLine); overload;
+    procedure StrokeLine(const AP0, AP1: TBLPoint); overload;
+    procedure StrokeLine(const AX0, AY0, AX1, AY1: Double); overload;
+
+    procedure StrokeCircle(const ACircle: TBLCircle); overload;
+    procedure StrokeCircle(const ACX, ACY, AR: Double); overload;
+
+    procedure StrokeEllipse(const AEllipse: TBLEllipse); overload;
+    procedure StrokeEllipse(const ACX, ACY, ARX, ARY: Double); overload;
+
+    procedure StrokeRoundRect(const ARoundRect: TBLRoundRect); overload;
+    procedure StrokeRoundRect(const ARect: TBLRect; const AR: Double); overload;
+    procedure StrokeRoundRect(const ARect: TBLRect; const ARX, ARY: Double); overload;
+    procedure StrokeRoundRect(const AX, AY, AW, AH, AR: Double); overload;
+    procedure StrokeRoundRect(const AX, AY, AW, AH, ARX, ARY: Double); overload;
+
+    procedure StrokeArc(const AArc: TBLArc); overload;
+    procedure StrokeArc(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure StrokeArc(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    procedure StrokeChord(const AChord: TBLArc); overload;
+    procedure StrokeChord(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure StrokeChord(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    procedure StrokePie(const APie: TBLArc); overload;
+    procedure StrokePie(const ACX, ACY, AR, AStart, ASweep: Double); overload;
+    procedure StrokePie(const ACX, ACY, ARX, ARY, AStart, ASweep: Double); overload;
+
+    procedure StrokeTriangle(const ATriangle: TBLTriangle); overload;
+    procedure StrokeTriangle(const AX0, AY0, AX1, AY1, AX2, AY2: Double); overload;
+
+    procedure StrokePolyline(const APoly: TArray<TBLPoint>); overload;
+    procedure StrokePolyline(const APoly: TBLArrayView<TBLPoint>); overload;
+    procedure StrokePolyline(const APoly: PBLPoint; const ACount: Integer); overload;
+    procedure StrokePolyline(const APoly: TArray<TBLPointI>); overload;
+    procedure StrokePolyline(const APoly: TBLArrayView<TBLPointI>); overload;
+    procedure StrokePolyline(const APoly: PBLPointI; const ACount: Integer); overload;
+
+    procedure StrokePolygon(const APoly: TArray<TBLPoint>); overload;
+    procedure StrokePolygon(const APoly: TBLArrayView<TBLPoint>); overload;
+    procedure StrokePolygon(const APoly: PBLPoint; const ACount: Integer); overload;
+    procedure StrokePolygon(const APoly: TArray<TBLPointI>); overload;
+    procedure StrokePolygon(const APoly: TBLArrayView<TBLPointI>); overload;
+    procedure StrokePolygon(const APoly: PBLPointI; const ACount: Integer); overload;
+
+    procedure StrokeBoxArray(const ABoxes: TArray<TBLBox>); overload;
+    procedure StrokeBoxArray(const ABoxes: TBLArrayView<TBLBox>); overload;
+    procedure StrokeBoxArray(const ABoxes: PBLBox; const ACount: Integer); overload;
+    procedure StrokeBoxArray(const ABoxes: TArray<TBLBoxI>); overload;
+    procedure StrokeBoxArray(const ABoxes: TBLArrayView<TBLBoxI>); overload;
+    procedure StrokeBoxArray(const ABoxes: PBLBoxI; const ACount: Integer); overload;
+
+    procedure StrokeRectArray(const ARects: TArray<TBLRect>); overload;
+    procedure StrokeRectArray(const ARects: TBLArrayView<TBLRect>); overload;
+    procedure StrokeRectArray(const ARects: PBLRect; const ACount: Integer); overload;
+    procedure StrokeRectArray(const ARects: TArray<TBLRectI>); overload;
+    procedure StrokeRectArray(const ARects: TBLArrayView<TBLRectI>); overload;
+    procedure StrokeRectArray(const ARects: PBLRectI; const ACount: Integer); overload;
+
+    procedure StrokePath(const APath: IBLPath);
+
+    procedure StrokeText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: String); overload;
+    procedure StrokeText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: String); overload;
+    procedure StrokeText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: UTF8String); overload;
+    procedure StrokeText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: UTF8String); overload;
+    procedure StrokeText(const ADst: TBLPointI; const AFont: IBLFont;
+      const AText: UCS4String); overload;
+    procedure StrokeText(const ADst: TBLPoint; const AFont: IBLFont;
+      const AText: UCS4String); overload;
+
+    procedure StrokeGlyphRun(const ADst: TBLPointI; const AFont: IBLFont;
+      const AGlyphRun: TBLGlyphRun); overload;
+    procedure StrokeGlyphRun(const ADst: TBLPoint; const AFont: IBLFont;
+      const AGlyphRun: TBLGlyphRun); overload;
+
+    procedure BlitImage(const ADst: TBLPoint; const ASrc: IBLImage); overload;
+    procedure BlitImage(const ADst: TBLPointI; const ASrc: IBLImage); overload;
+
+    procedure BlitImage(const ADst: TBLPoint; const ASrc: IBLImage;
+      const ASrcArea: TBLRectI); overload;
+    procedure BlitImage(const ADst: TBLPointI; const ASrc: IBLImage;
+      const ASrcArea: TBLRectI); overload;
+
+    procedure BlitImage(const ADst: TBLRect; const ASrc: IBLImage); overload;
+    procedure BlitImage(const ADst: TBLRectI; const ASrc: IBLImage); overload;
+
+    procedure BlitImage(const ADst: TBLRect; const ASrc: IBLImage;
+      const ASrcArea: TBLRectI); overload;
+    procedure BlitImage(const ADst: TBLRectI; const ASrc: IBLImage;
+      const ASrcArea: TBLRectI); overload;
+  public
+    procedure AfterConstruction; override;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    { Creates a default constructed rendering context.
+
+      Default constructed means that the instance is valid, but uninitialized,
+      which means the rendering context does not have attached any target. Any
+      attempt to use uninitialized context results in
+      TBLResultCode.NotInitialized error. }
+    constructor Create; overload;
+
+    { Creates a new rendering context for rendering to the image ATarget. }
+    constructor Create(const ATarget: IBLImage); overload;
+
+    { Creates a new rendering context for rendering to the image ATarget.
+
+      This overload accepts create options that can be used to change the
+      implementation of the rendering context. }
+    constructor Create(const ATarget: IBLImage;
+      const ACreateInfo: TBLContextCreateInfo); overload;
+
+    destructor Destroy; override;
+
+    function Equals(Obj: TObject): Boolean; overload; override;
+  end;
+{$ENDREGION 'Context'}
+
+{$REGION 'Runtime'}
+
+{ ============================================================================
+   [Constants]
+  ============================================================================ }
+
+{ Blend2D runtime limits.
+
+  Note: These constanst are used across Blend2D, but they are not designed to
+  be ABI stable. New versions of Blend2D can increase certain limits without
+  notice. Use runtime to query the limits dynamically, see
+  TBLRuntimeBuildInfo. }
+
+const
+  { Maximum width and height of an image. }
+  BL_MAX_IMAGE_SIZE   = BL_RUNTIME_MAX_IMAGE_SIZE;
+
+  { Maximum number of threads for asynchronous operations (including rendering). }
+  BL_MAX_THREAD_COUNT =  BL_RUNTIME_MAX_THREAD_COUNT;
+
+{ ============================================================================
+   [Enums]
+  ============================================================================ }
+
+type
+  { Blend2D runtime build type. }
+  TBLRuntimeBuildType = (
+    { Describes a Blend2D debug build. }
+    Debug   = BL_RUNTIME_BUILD_TYPE_DEBUG,
+
+    { Describes a Blend2D release build. }
+    Release = BL_RUNTIME_BUILD_TYPE_RELEASE);
+
+type
+  { CPU architectures }
+  TBLRuntimeCpuArch = (
+    { Unknown architecture. }
+    Unknown = BL_RUNTIME_CPU_ARCH_UNKNOWN,
+
+    { 32-bit or 64-bit X86 architecture. }
+    X86     = BL_RUNTIME_CPU_ARCH_X86,
+
+    { 32-bit or 64-bit ARM architecture. }
+    ARM     = BL_RUNTIME_CPU_ARCH_ARM,
+
+    { 32-bit or 64-bit MIPS architecture. }
+    MIPS    = BL_RUNTIME_CPU_ARCH_MIPS);
+
+type
+  {! CPU features Blend2D supports. }
+  TBLRuntimeCpuFeature = (
+    SSE2   = 0,
+    SSE3   = 1,
+    SSSE3  = 2,
+    SSE4_1 = 3,
+    SSE4_2 = 4,
+    AVX    = 5,
+    AVX2   = 6);
+  TBLRuntimeCpuFeatures = set of TBLRuntimeCpuFeature;
+
+type
+  { Runtime cleanup flags that can be used through BLRuntime.Cleanup }
+  TBLRuntimeCleanupFlag = (
+    { Cleanup object memory pool. }
+    ObjectPool = 0,
+
+    { Cleanup zeroed memory pool. }
+    ZeroedPool = 1,
+
+    { Cleanup thread pool (would join unused threads). }
+    ThreadPool = 4);
+  TBLRuntimeCleanupFlags = set of TBLRuntimeCleanupFlag;
+
+type
+  _TBLRuntimeCleanupFlagsHelper = record helper for TBLRuntimeCleanupFlags
+  public const
+    Everything = [TBLRuntimeCleanupFlag.ObjectPool,
+                  TBLRuntimeCleanupFlag.ZeroedPool,
+                  TBLRuntimeCleanupFlag.ThreadPool];
+  end;
+
+{ ============================================================================
+   [BLRuntime - BuildInfo]
+  ============================================================================ }
+
+type
+  { Blend2D build information. }
+  TBLRuntimeBuildInfo = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRuntimeBuildInfo;
+    function GetBuildType: TBLRuntimeBuildType; inline;
+    function GetBaselineCpuFeatures: TBLRuntimeCpuFeatures; inline;
+    function GetSupportedCpuFeatures: TBLRuntimeCpuFeatures; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    { Blend2D version stored as (Major shl 16) or (Minor shl 8) or Patch }
+    property Version: Cardinal read FHandle.version.version;
+
+    { Decomposed Blend2D version }
+    property PatchVersion: Byte read FHandle.version.patchVersion;
+    property MinorVersion: Byte read FHandle.version.minorVersion;
+    property MajorVersion: Word read FHandle.version.majorVersion;
+
+    { Blend2D build type }
+    property BuildType: TBLRuntimeBuildType read GetBuildType;
+
+    { Baseline CPU features.
+
+      These features describe CPU features that were detected at compile-time.
+      Baseline features are used to compile all source files so they represent
+      the minimum feature-set the target CPU must support to run Blend2D.
+
+      Official Blend2D builds set baseline at SSE2 on X86 target and NEON on
+      ARM target. Custom builds can set use different baseline. }
+    property BaselineCpuFeatures: TBLRuntimeCpuFeatures read GetBaselineCpuFeatures;
+
+    { Supported CPU features.
+
+      These features do not represent the features that the host CPU must
+      support, instead, they represent all features that Blend2D can take
+      advantage of in C++ code that uses instruction intrinsics. For example if
+      AVX2 is part of SupportedCpuFeatures it means that Blend2D can take
+      advantage of it if there is a separate code-path. }
+    property SupportedCpuFeatures: TBLRuntimeCpuFeatures read GetSupportedCpuFeatures;
+
+    { Maximum size of an image (both width and height). }
+    property MaxImageSize: Integer read FHandle.maxImageSize;
+
+    { Maximum number of threads for asynchronous operations, including
+      rendering. }
+    property MaxThreadCount: Integer read FHandle.maxThreadCount;
+  end;
+  PBLRuntimeBuildInfo = ^TBLRuntimeBuildInfo;
+
+{ ============================================================================
+   [BLRuntime - SystemInfo]
+  ============================================================================ }
+
+type
+  { System information queried by the runtime. }
+  TBLRuntimeSystemInfo = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRuntimeSystemInfo;
+    function GetCpuArch: TBLRuntimeCpuArch; inline;
+    function GetCpuFeatures: TBLRuntimeCpuFeatures; inline;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    { Host CPU architecture }
+    property CpuArch: TBLRuntimeCpuArch read GetCpuArch;
+
+    { Host CPU features }
+    property CpuFeatures: TBLRuntimeCpuFeatures read GetCpuFeatures;
+
+    { Number of cores of the host CPU/CPUs. }
+    property CoreCount: Integer read FHandle.coreCount;
+
+    { Number of threads of the host CPU/CPUs. }
+    property ThreadCount: Integer read FHandle.threadCount;
+
+    { Minimum stack size of a worker thread used by Blend2D. }
+    property ThreadStackSize: Integer read FHandle.threadStackSize;
+
+    { Allocation granularity of virtual memory (includes thread's stack). }
+    property AllocationGranularity: Integer read FHandle.allocationGranularity;
+  end;
+  PBLRuntimeSystemInfo = ^TBLRuntimeSystemInfo;
+
+{ ============================================================================
+   [BLRuntime - MemoryInfo]
+  ============================================================================ }
+
+type
+  { Provides information about resources allocated by Blend2D. }
+  TBLRuntimeResourceInfo = record
+  {$REGION 'Internal Declarations'}
+  private
+    FHandle: BLRuntimeResourceInfo;
+  {$ENDREGION 'Internal Declarations'}
+  public
+    { Virtual memory used at this time. }
+    property VMUsed: NativeInt read FHandle.vmUsed;
+
+    { Virtual memory reserved (allocated internally). }
+    property VMReserved: NativeInt read FHandle.vmReserved;
+
+    { Overhead required to manage virtual memory allocations. }
+    property VMOverhead: NativeInt read FHandle.vmOverhead;
+
+    { Number of blocks of virtual memory allocated. }
+    property VMBlockCount: NativeInt read FHandle.vmBlockCount;
+
+    { Zeroed memory used at this time. }
+    property ZMUsed: NativeInt read FHandle.zmUsed;
+
+    { Zeroed memory reserved (allocated internally). }
+    property ZMReserved: NativeInt read FHandle.zmReserved;
+
+    { Overhead required to manage zeroed memory allocations. }
+    property ZMOverhead: NativeInt read FHandle.zmOverhead;
+
+    { Number of blocks of zeroed memory allocated. }
+    property ZMBlockCount: NativeInt read FHandle.zmBlockCount;
+
+    { Count of dynamic pipelines created and cached. }
+    property DynamicPipelineCount: NativeInt read FHandle.dynamicPipelineCount;
+
+    { Number of active file handles used by Blend2D.
+
+      Note: File handles are counted by IBLFile - when a file is opened a global
+      counter is incremented and when it's closed it's decremented.
+      This means that this number represents the actual use of IBLFile and
+      doesn't consider the origin of the use (it's either Blend2D or user). }
+    property FileHandleCount: NativeInt read FHandle.fileHandleCount;
+
+    { Number of active file mappings used by Blend2D.
+
+      Note: Blend2D maps file content to TBytes container, so this number
+      represents the actual number of TBytes instances that contain a mapped
+      file. }
+    property FileMappingCount: NativeInt read FHandle.fileMappingCount;
+  end;
+  PBLRuntimeMemoryInfo = ^TBLRuntimeResourceInfo;
+
+{ ============================================================================
+   [BLRuntime]
+  ============================================================================ }
+
+type
+  TBLRuntime = class // static
+  public
+    class procedure Cleanup(const AFlags: TBLRuntimeCleanupFlags); static;
+    class procedure QueryBuildInfo(out AInfo: TBLRuntimeBuildInfo); static;
+    class procedure QuerySystemInfo(out AInfo: TBLRuntimeSystemInfo); static;
+    class procedure QueryResourceInfo(out AInfo: TBLRuntimeResourceInfo); static;
+    class procedure LogMessage(const AMessage: String); overload; static;
+    class procedure LogMessage(const AMessage: String; const AArgs: array of const); overload; static;
+  end;
+
+{$ENDREGION 'Runtime'}
+
+{$REGION 'Internal'}
+
+procedure _BLCheck(const AResult: BLResultCode);
+
+{$ENDREGION 'Internal'}
+
+implementation
+
+uses
+  System.TypInfo;
+
+{$POINTERMATH ON}
+
+{$REGION 'Utils'}
+
+type
+  IBLArray = interface
+  ['{F0CABAA5-F756-483D-95F1-4EBC134793D9}']
+    function Handle: PBLArrayCore;
+    procedure RevokeOwnership;
+  end;
+
+type
+  TBLArray = class(TInterfacedObject, IBLArray)
+  private
+    FHandle: BLArrayCore;
+    FIsReference: Boolean;
+  protected
+    { IBLArray }
+    function Handle: PBLArrayCore;
+    procedure RevokeOwnership;
+  public
+    constructor Create(const AType: BLImplType);
+    destructor Destroy; override;
+  end;
+
+type
+  TBLUtils = class // static
+  public
+    class function ArrayElementType<T>: BLImplType; static;
+    class function CreateBLArray<T: record>: IBLArray; static;
+    class function BLArrayToArray<T: record>(const AArray: BLArrayCore): TArray<T>; overload; static;
+    class function BLArrayToArray<T: record>(const AArray: IBLArray): TArray<T>; overload; static;
+    class function ArrayToBLArray<T: record>(const AArray: TArray<T>): IBLArray; static;
+  end;
+
+{ TBLArray }
+
+constructor TBLArray.Create(const AType: BLImplType);
+begin
+  inherited Create;
+  blArrayInit(@FHandle, AType);
+end;
+
+destructor TBLArray.Destroy;
+begin
+  if (not FIsReference) then
+    blArrayDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLArray.Handle: PBLArrayCore;
+begin
+  Result := @FHandle;
+end;
+
+procedure TBLArray.RevokeOwnership;
+begin
+  FIsReference := True;
+end;
+
+{ TBLUtils }
+
+class function TBLUtils.ArrayElementType<T>: BLImplType;
+var
+  Info: PTypeInfo;
+  Data: PTypeData;
+begin
+  Info := TypeInfo(T);
+  case GetTypeKind(T) of
+    tkInteger,
+    tkEnumeration:
+      case GetTypeData(Info)^.OrdType of
+        otSByte: Exit(BL_IMPL_TYPE_ARRAY_I8);
+        otUByte: Exit(BL_IMPL_TYPE_ARRAY_U8);
+        otSWord: Exit(BL_IMPL_TYPE_ARRAY_I16);
+        otUWord: Exit(BL_IMPL_TYPE_ARRAY_U16);
+        otSLong: Exit(BL_IMPL_TYPE_ARRAY_I32);
+        otULong: Exit(BL_IMPL_TYPE_ARRAY_U32);
+      end;
+
+    tkInt64:
+      begin
+        Data := GetTypeData(Info);
+        if (Data^.MaxInt64Value > Data^.MinInt64Value) then
+          Exit(BL_IMPL_TYPE_ARRAY_I64)
+        else
+          Exit(BL_IMPL_TYPE_ARRAY_U64);
+      end;
+
+    tkFloat:
+      begin
+        Data := GetTypeData(Info);
+        case Data^.FloatType of
+          ftSingle  : Exit(BL_IMPL_TYPE_ARRAY_F32);
+          ftDouble  : Exit(BL_IMPL_TYPE_ARRAY_F64);
+        end;
+      end;
+
+    tkRecord:
+      case SizeOf(T) of
+         1: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_1);
+         2: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_2);
+         3: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_3);
+         4: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_4);
+         6: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_6);
+         8: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_8);
+        10: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_10);
+        12: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_12);
+        16: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_16);
+        20: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_20);
+        24: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_24);
+        32: Exit(BL_IMPL_TYPE_ARRAY_STRUCT_32);
+      end;
+  end;
+
+  Assert(False, 'Unsupported array element type');
+  Result := BL_IMPL_TYPE_NULL;
+end;
+
+class function TBLUtils.ArrayToBLArray<T>(const AArray: TArray<T>): IBLArray;
+var
+  A: PBLArrayCore;
+  Count: Integer;
+begin
+  Result := TBLArray.Create(ArrayElementType<T>);
+
+  Count := Length(AArray);
+  if (Count <> 0) then
+  begin
+    A := Result.Handle;
+    _BLCheck(blArrayReserve(A, Count));
+    _BLCheck(blArrayAppendView(A, @AArray[0], Count));
+  end;
+end;
+
+class function TBLUtils.BLArrayToArray<T>(const AArray: BLArrayCore): TArray<T>;
+var
+  Impl: PBLArrayImpl;
+  Count: Integer;
+begin
+  Impl := AArray.impl;
+  Assert(Assigned(Impl) and (Impl.itemSize = SizeOf(T)));
+
+  Count := Impl.size;
+  if (Count = 0) then
+    Exit(nil);
+
+  SetLength(Result, Count);
+  Move(Impl.data^, Result[0], Count * SizeOf(T));
+end;
+
+class function TBLUtils.BLArrayToArray<T>(const AArray: IBLArray): TArray<T>;
+var
+  Impl: PBLArrayImpl;
+  Count: Integer;
+begin
+  Impl := AArray.Handle.impl;
+  Assert(Assigned(Impl) and (Impl.itemSize = SizeOf(T)));
+
+  Count := Impl.size;
+  if (Count = 0) then
+    Exit(nil);
+
+  SetLength(Result, Count);
+  Move(Impl.data^, Result[0], Count * SizeOf(T));
+end;
+
+class function TBLUtils.CreateBLArray<T>: IBLArray;
+begin
+  Result := TBLArray.Create(ArrayElementType<T>);
+end;
+
+{$ENDREGION 'Utils'}
+
+{$REGION 'Error Handling'}
+
+var
+  GErrorHandler: TBLErrorHandler = nil;
+  GErrorUserData: Pointer = nil;
+  GLastError: TBLResultCode = TBLResultCode.Success;
+
+procedure BLSetErrorHandler(const AHandler: TBLErrorHandler;
+  const AUserData: Pointer);
+begin
+  GErrorHandler := AHandler;
+  GErrorUserData := AUserData;
+end;
+
+procedure ExceptionErrorHandler(const AResultCode: TBLResultCode;
+  const AUserData: Pointer);
+begin
+  raise EBlend2DError.Create(AResultCode);
+end;
+
+procedure BLSetExceptionErrorHandler;
+begin
+  GErrorHandler := ExceptionErrorHandler;
+  GErrorUserData := nil;
+end;
+
+procedure GetLastErrorHandler(const AResultCode: TBLResultCode;
+  const AUserData: Pointer);
+begin
+  GLastError := AResultCode;
+end;
+
+function BLGetLastError: TBLResultCode;
+begin
+  Result := GLastError;
+  GLastError := TBLResultCode.Success;
+end;
+
+procedure BLSetGetLastErrorHandler;
+begin
+  GErrorHandler := GetLastErrorHandler;
+  GErrorUserData := nil;
+end;
+
+{ _TBLResultCodeHelper }
+
+function _TBLResultCodeHelper.ToString: String;
+const
+  ERROR_STRINGS: array [BL_ERROR_START_INDEX..Ord(High(TBLResultCode))] of String = (
+    'Out of memory',
+    'Invalid value/argument',
+    'Invalid state',
+    'Invalid handle or file.',
+    'Value too large',
+    'Not initialized (some instance is built-in none when it shouldn''t be).',
+    'Not implemented',
+    'Operation not permitted',
+    'IO error',
+    'Device or resource busy',
+    'Operation interrupted',
+    'Try again',
+    'Timed out',
+    'Broken pipe',
+    'File is not seekable',
+    'Too many levels of symlinks',
+    'File is too large',
+    'File/directory already exists',
+    'Access denied',
+    'Media changed',
+    'The file/FS is read-only',
+    'Device doesn''t exist',
+    'Not found, no entry (fs)',
+    'No media in drive/device',
+    'No more data / end of file',
+    'No more files',
+    'No space left on device',
+    'Directory is not empty',
+    'Not a file',
+    'Not a directory',
+    'Not same device',
+    'Not a block device',
+    'File/path name is invalid',
+    'File/path name is too long',
+    'Too many open files',
+    'Too many open files by OS',
+    'Too many symbolic links on FS',
+    'Too many threads',
+    'Thread pool is exhausted and couldn''t acquire the requested thread count',
+    'File is empty (not specific to any OS error).',
+    'File open failed',
+    'Not a root device/directory',
+    'Unknown system error that failed to translate to Blend2D result code.',
+    'Invalid data alignment.',
+    'Invalid data signature or header.',
+    'Invalid or corrupted data.',
+    'Invalid string (invalid data of either UTF8, UTF16, or UTF32).',
+    'Truncated data (more data required than memory/stream provides).',
+    'Input data too large to be processed.',
+    'Decompression failed due to invalid data (RLE, Huffman, etc).',
+    'Invalid geometry (invalid path data or shape).',
+    'Returned when there is no matching vertex in path data.',
+    'No matching cookie (BLContext).',
+    'No states to restore (BLContext).',
+    'The size of the image is too large.',
+    'Image codec for a required format doesn''t exist.',
+    'Unknown or invalid file format that cannot be read.',
+    'Image codec doesn''t support reading the file format.',
+    'Image codec doesn''t support writing the file format.',
+    'Multiple IHDR chunks are not allowed (PNG).',
+    'Invalid IDAT chunk (PNG).',
+    'Invalid IEND chunk (PNG).',
+    'Invalid PLTE chunk (PNG).',
+    'Invalid tRNS chunk (PNG).',
+    'Invalid filter type (PNG).',
+    'Unsupported feature (JPEG).',
+    'Invalid SOS marker or header (JPEG).',
+    'Invalid SOF marker (JPEG).',
+    'Multiple SOF markers (JPEG).',
+    'Unsupported SOF marker (JPEG).',
+    'Font doesn''t have any data as it''s not initialized.',
+    'Font or font-face was not matched (TBLFontManager).',
+    'Font has no character to glyph mapping data.',
+    'Font has missing an important table.',
+    'Font feature is not available.',
+    'Font has an invalid CFF data.',
+    'Font program terminated because the execution reached the limit.',
+    'Invalid glyph identifier.');
+begin
+  if (Self = TBLResultCode.Success) then
+    Result := 'Success'
+  else if (Ord(Self) >= Low(ERROR_STRINGS)) and (Ord(Self) <= High(ERROR_STRINGS)) then
+    Result := ERROR_STRINGS[Ord(Self)]
+  else
+    Result := Format('Unknown error (%d)', [Ord(Self)]);
+end;
+
+{ EBlend2DError }
+
+constructor EBlend2DError.Create(const AResultCode: TBLResultCode);
+begin
+  inherited Create(AResultCode.ToString);
+  FResultCode := AResultCode;
+end;
+
+{$ENDREGION 'Error Handling'}
+
+{$REGION 'General'}
+
+{ TBLRange }
+
+function BLRange(const AStart, AFinish: Integer): TBLRange; inline;
+begin
+  Result.Reset(AStart, AFinish);
+end;
+
+class operator TBLRange.Equal(const ALeft, ARight: TBLRange): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLRange.Equals(const AOther: TBLRange): Boolean;
+begin
+  Result := (FHandle.start = AOther.FHandle.start) and
+            (FHandle.&end = AOther.FHandle.&end);
+end;
+
+function TBLRange.GetFinish: Integer;
+begin
+  Result := FHandle.&end;
+end;
+
+function TBLRange.GetStart: Integer;
+begin
+  Result := FHandle.start;
+end;
+
+class operator TBLRange.NotEqual(const ALeft, ARight: TBLRange): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLRange.Reset;
+begin
+  FHandle.start := 0;
+  FHandle.&end := 0;
+end;
+
+procedure TBLRange.Reset(const AStart, AFinish: Integer);
+begin
+  FHandle.start := AStart;
+  FHandle.&end := AFinish;
+end;
+
+procedure TBLRange.SetFinish(const AValue: Integer);
+begin
+  FHandle.&end := AValue;
+end;
+
+procedure TBLRange.SetStart(const AValue: Integer);
+begin
+  FHandle.start := AValue;
+end;
+
+{$ENDREGION 'General'}
+
+{$REGION 'Array'}
+
+{ TBLArrayView<T> }
+
+function TBLArrayView<T>.GetLast: Pointer;
+begin
+  Result := FHandle.data;
+  Inc(P(Result), FHandle.size);
+end;
+
+function TBLArrayView<T>.GetLength: Integer;
+begin
+  Result := FHandle.size;
+end;
+
+procedure TBLArrayView<T>.Reset;
+begin
+  FHandle.data := nil;
+  FHandle.size := 0;
+end;
+
+procedure TBLArrayView<T>.Reset(const AData: Pointer; const ALength: Integer);
+begin
+  FHandle.data := AData;
+  FHandle.size := ALength;
+end;
+
+{$ENDREGION 'Array'}
+
+{$REGION 'Color'}
+
+{ TBLRgba32 }
+
+function BLRgba32: TBLRgba32; overload; inline;
+begin
+  Result.FHandle.value := 0;
+end;
+
+function BLRgba32(const AValue: Cardinal): TBLRgba32; inline;
+begin
+  Result.FHandle.value := AValue;
+end;
+
+function BLRgba32(const AR, AG, AB: Byte; const AA: Byte = 255): TBLRgba32; overload; inline;
+begin
+  Result.Reset(AR, AG, AB, AA);
+end;
+
+function BLRgba32(const AValue: TBLRgba64): TBLRgba32; overload; inline;
+begin
+  Result.Reset(AValue);
+end;
+
+function BLRgba32(const AValue: TBLRgba): TBLRgba32; overload; inline;
+begin
+  Result.Reset(AValue);
+end;
+
+class operator TBLRgba32.Implicit(const AValue: Cardinal): TBLRgba32;
+begin
+  Result.FHandle.value := AValue;
+end;
+
+class operator TBLRgba32.Equal(const ALeft, ARight: TBLRgba32): Boolean;
+begin
+  Result := (ALeft.FHandle.value = ARight.FHandle.value);
+end;
+
+function TBLRgba32.GetIsOpaque: Boolean;
+begin
+  Result := (FHandle.value >= $FF000000);
+end;
+
+function TBLRgba32.GetIsTransparent: Boolean;
+begin
+  Result := (FHandle.value <= $00FFFFFF);
+end;
+
+class operator TBLRgba32.Implicit(const AValue: TBLRgba32): Cardinal;
+begin
+  Result := AValue.FHandle.value;
+end;
+
+class operator TBLRgba32.NotEqual(const ALeft, ARight: TBLRgba32): Boolean;
+begin
+  Result := (ALeft.FHandle.value <> ARight.FHandle.value);
+end;
+
+procedure TBLRgba32.Reset;
+begin
+  FHandle.value := 0;
+end;
+
+procedure TBLRgba32.Reset(const AValue: Cardinal);
+begin
+  FHandle.value := AValue;
+end;
+
+procedure TBLRgba32.Reset(const AR, AG, AB, AA: Byte);
+begin
+  FHandle.value := (AA shl 24) or (AR shl 16) or (AG shl 8) or AB;
+end;
+
+{ TBLRgba64 }
+
+function BLRgba64: TBLRgba64; overload; inline;
+begin
+  Result.FHandle.value := 0;
+end;
+
+function BLRgba64(const AValue: UInt64): TBLRgba64; overload; inline;
+begin
+  Result.FHandle.value := AValue;
+end;
+
+function BLRgba64(const AR, AG, AB: Word; const AA: Word = $FFFF): TBLRgba64; overload; inline;
+begin
+  Result.Reset(AR, AG, AB, AA);
+end;
+
+function BLRgba64(const AValue: TBLRgba32): TBLRgba64; overload; inline;
+begin
+  Result.Reset(AValue);
+end;
+
+function BLRgba64(const AValue: TBLRgba): TBLRgba32; overload; inline;
+begin
+  Result.Reset(AValue);
+end;
+
+class operator TBLRgba64.Equal(const ALeft, ARight: TBLRgba64): Boolean;
+begin
+  Result := (ALeft.FHandle.value = ARight.FHandle.value);
+end;
+
+function TBLRgba64.GetIsOpaque: Boolean;
+begin
+  Result := (FHandle.value >= $FFFF000000000000);
+end;
+
+function TBLRgba64.GetIsTransparent: Boolean;
+begin
+  Result := (FHandle.value <= $0000FFFFFFFFFFFF);
+end;
+
+class operator TBLRgba64.Implicit(const AValue: UInt64): TBLRgba64;
+begin
+  Result.FHandle.value := AValue;
+end;
+
+class operator TBLRgba64.Implicit(const AValue: TBLRgba64): UInt64;
+begin
+  Result := AValue.FHandle.value;
+end;
+
+class operator TBLRgba64.NotEqual(const ALeft, ARight: TBLRgba64): Boolean;
+begin
+  Result := (ALeft.FHandle.value <> ARight.FHandle.value);
+end;
+
+procedure TBLRgba64.Reset(const AValue: TBLRgba32);
+begin
+  FHandle.r := AValue.FHandle.r or (AValue.FHandle.r shl 8);
+  FHandle.g := AValue.FHandle.g or (AValue.FHandle.g shl 8);
+  FHandle.b := AValue.FHandle.b or (AValue.FHandle.b shl 8);
+  FHandle.a := AValue.FHandle.a or (AValue.FHandle.a shl 8);
+end;
+
+procedure TBLRgba64.Reset(const AR, AG, AB, AA: Word);
+begin
+  FHandle.value := (UInt64(AA) shl 48) or (UInt64(AR) shl 32)
+                or (UInt64(AG) shl 16) or UInt64(AB);
+end;
+
+procedure TBLRgba64.Reset(const AValue: UInt64);
+begin
+  FHandle.value := AValue;
+end;
+
+procedure TBLRgba64.Reset;
+begin
+  FHandle.value := 0;
+end;
+
+{ TBLRgba }
+
+function BLRgba: TBLRgba; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLRgba(const AR, AG, AB: Single; const AA: Single = 1): TBLRgba; overload; inline;
+begin
+  Result.Reset(AR, AG, AB, AA);
+end;
+
+function BLRgba(const ARgba: TBLRgba32): TBLRgba; overload; inline;
+begin
+  Result.Reset(ARgba);
+end;
+
+function BLRgba(const ARgba: TBLRgba64): TBLRgba; overload; inline;
+begin
+  Result.Reset(ARgba);
+end;
+
+class operator TBLRgba.Equal(const ALeft, ARight: TBLRgba): Boolean;
+begin
+  Result := (ALeft.FHandle.r = ARight.FHandle.r)
+        and (ALeft.FHandle.g = ARight.FHandle.g)
+        and (ALeft.FHandle.b = ARight.FHandle.b)
+        and (ALeft.FHandle.a = ARight.FHandle.a);
+end;
+
+class operator TBLRgba.Equal(const ALeft: TBLRgba;
+  const ARight: TBLRgba32): Boolean;
+begin
+  Result := (ALeft = BLRgba(ARight));
+end;
+
+class operator TBLRgba.Equal(const ALeft: TBLRgba;
+  const ARight: TBLRgba64): Boolean;
+begin
+  Result := (ALeft = BLRgba(ARight));
+end;
+
+function TBLRgba.GetIsOpaque: Boolean;
+begin
+  Result := (FHandle.a >= 1);
+end;
+
+function TBLRgba.GetIsTransparent: Boolean;
+begin
+  Result := (FHandle.a = 0);
+end;
+
+class operator TBLRgba.NotEqual(const ALeft: TBLRgba;
+  const ARight: TBLRgba32): Boolean;
+begin
+  Result := (ALeft <> BLRgba(ARight));
+end;
+
+class operator TBLRgba.NotEqual(const ALeft: TBLRgba;
+  const ARight: TBLRgba64): Boolean;
+begin
+  Result := (ALeft <> BLRgba(ARight));
+end;
+
+class operator TBLRgba.NotEqual(const ALeft, ARight: TBLRgba): Boolean;
+begin
+  Result := not (ALeft = ARight);
+end;
+
+procedure TBLRgba.Reset(const ARgba: TBLRgba64);
+const
+  FACTOR = 1.0 / 65535.0;
+begin
+  FHandle.r := ARgba.R * FACTOR;
+  FHandle.g := ARgba.G * FACTOR;
+  FHandle.b := ARgba.B * FACTOR;
+  FHandle.a := ARgba.A * FACTOR;
+end;
+
+procedure TBLRgba.Reset(const ARgba: TBLRgba32);
+const
+  FACTOR = 1.0 / 255.0;
+begin
+  FHandle.r := ARgba.R * FACTOR;
+  FHandle.g := ARgba.G * FACTOR;
+  FHandle.b := ARgba.B * FACTOR;
+  FHandle.a := ARgba.A * FACTOR;
+end;
+
+procedure TBLRgba.Reset;
+begin
+  FHandle.r := 0;
+  FHandle.g := 0;
+  FHandle.b := 0;
+  FHandle.a := 0;
+end;
+
+procedure TBLRgba.Reset(const AR, AG, AB, AA: Single);
+begin
+  FHandle.r := AR;
+  FHandle.g := AG;
+  FHandle.b := AB;
+  FHandle.a := AA;
+end;
+
+{ _TBLRgba32Helper }
+
+procedure _TBLRgba32Helper.Reset(const AValue: TBLRgba64);
+var
+  Hi, Lo: UInt32;
+begin
+  Hi := AValue.FHandle.value shr 32;
+  Lo := AValue.FHandle.value;
+  FHandle.value :=  (Hi and $FF000000)         or
+                   ((Lo and $FF000000) shr 16) or
+                   ((Hi and $0000FF00) shl  8) or
+                   ((Lo and $0000FF00) shr  8);
+end;
+
+procedure _TBLRgba32Helper.Reset(const AValue: TBLRgba);
+begin
+  FHandle.a := EnsureRange(Trunc(AValue.A * 255.0), 0, 255);
+  FHandle.r := EnsureRange(Trunc(AValue.R * 255.0), 0, 255);
+  FHandle.g := EnsureRange(Trunc(AValue.G * 255.0), 0, 255);
+  FHandle.b := EnsureRange(Trunc(AValue.B * 255.0), 0, 255);
+end;
+
+{ _TBLRgba64Helper }
+
+procedure _TBLRgba64Helper.Reset(const AValue: TBLRgba);
+begin
+  FHandle.a := EnsureRange(Trunc(AValue.A * 65535.0), 0, 65535);
+  FHandle.r := EnsureRange(Trunc(AValue.R * 65535.0), 0, 65535);
+  FHandle.g := EnsureRange(Trunc(AValue.G * 65535.0), 0, 65535);
+  FHandle.b := EnsureRange(Trunc(AValue.B * 65535.0), 0, 65535);
+end;
+
+{$ENDREGION 'Color'}
+
+{$REGION 'Geometry'}
+
+function BLPointI: TBLPointI; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLPointI(const AX, AY: Integer): TBLPointI; overload; inline;
+begin
+  Result.Reset(AX, AY);
+end;
+
+{ TBLPointI }
+
+class operator TBLPointI.Add(const ALeft, ARight: TBLPointI): TBLPointI;
+begin
+  Result.Reset(ALeft.FHandle.x + ARight.FHandle.x, ALeft.FHandle.y + ARight.FHandle.y);
+end;
+
+class operator TBLPointI.Add(const ALeft: Integer;
+  const ARight: TBLPointI): TBLPointI;
+begin
+  Result.Reset(ALeft + ARight.FHandle.x, ALeft + ARight.FHandle.y);
+end;
+
+class operator TBLPointI.Add(const ALeft: TBLPointI;
+  const ARight: Integer): TBLPointI;
+begin
+  Result.Reset(ALeft.FHandle.x + ARight, ALeft.FHandle.y + ARight);
+end;
+
+class operator TBLPointI.Equal(const ALeft, ARight: TBLPointI): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLPointI.Equals(const AOther: TBLPointI): Boolean;
+begin
+  Result := (FHandle.x = AOther.FHandle.x)
+        and (FHandle.y = AOther.FHandle.y);
+end;
+
+class operator TBLPointI.IntDivide(const ALeft: TBLPointI;
+  const ARight: Integer): TBLPointI;
+begin
+  Result.Reset(ALeft.FHandle.x div ARight, ALeft.FHandle.y div ARight);
+end;
+
+class operator TBLPointI.IntDivide(const ALeft: Integer;
+  const ARight: TBLPointI): TBLPointI;
+begin
+  Result.Reset(ALeft div ARight.FHandle.x, ALeft div ARight.FHandle.y);
+end;
+
+class operator TBLPointI.IntDivide(const ALeft, ARight: TBLPointI): TBLPointI;
+begin
+  Result.Reset(ALeft.FHandle.x div ARight.FHandle.x, ALeft.FHandle.y div ARight.FHandle.y);
+end;
+
+class operator TBLPointI.Multiply(const ALeft, ARight: TBLPointI): TBLPointI;
+begin
+  Result.Reset(ALeft.FHandle.x * ARight.FHandle.x, ALeft.FHandle.y * ARight.FHandle.y);
+end;
+
+class operator TBLPointI.Multiply(const ALeft: Integer;
+  const ARight: TBLPointI): TBLPointI;
+begin
+  Result.Reset(ALeft * ARight.FHandle.x, ALeft * ARight.FHandle.y);
+end;
+
+class operator TBLPointI.Multiply(const ALeft: TBLPointI;
+  const ARight: Integer): TBLPointI;
+begin
+  Result.Reset(ALeft.FHandle.x * ARight, ALeft.FHandle.y * ARight);
+end;
+
+class operator TBLPointI.Negative(const AValue: TBLPointI): TBLPointI;
+begin
+  Result.Reset(-AValue.FHandle.x, -AValue.FHandle.y);
+end;
+
+class operator TBLPointI.NotEqual(const ALeft, ARight: TBLPointI): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLPointI.Reset(const AX, AY: Integer);
+begin
+  FHandle.x := AX;
+  FHandle.y := AY;
+end;
+
+class operator TBLPointI.Subtract(const ALeft: TBLPointI;
+  const ARight: Integer): TBLPointI;
+begin
+  Result.Reset(ALeft.FHandle.x - ARight, ALeft.FHandle.y - ARight);
+end;
+
+class operator TBLPointI.Subtract(const ALeft: Integer;
+  const ARight: TBLPointI): TBLPointI;
+begin
+  Result.Reset(ALeft - ARight.FHandle.x, ALeft - ARight.FHandle.y);
+end;
+
+class operator TBLPointI.Subtract(const ALeft, ARight: TBLPointI): TBLPointI;
+begin
+  Result.Reset(ALeft.FHandle.x - ARight.FHandle.x, ALeft.FHandle.y - ARight.FHandle.y);
+end;
+
+procedure TBLPointI.Reset;
+begin
+  FHandle.x := 0;
+  FHandle.y := 0;
+end;
+
+{ TBLSizeI }
+
+function BLSizeI: TBLSizeI; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLSizeI(const AW, AH: Integer): TBLSizeI; overload; inline;
+begin
+  Result.Reset(AW, AH);
+end;
+
+class operator TBLSizeI.Equal(const ALeft, ARight: TBLSizeI): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLSizeI.Equals(const AOther: TBLSizeI): Boolean;
+begin
+  Result := (FHandle.w = AOther.FHandle.w)
+        and (FHandle.h = AOther.FHandle.h);
+end;
+
+class operator TBLSizeI.NotEqual(const ALeft, ARight: TBLSizeI): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLSizeI.Reset(const AW, AH: Integer);
+begin
+  FHandle.w := AW;
+  FHandle.h := AH;
+end;
+
+procedure TBLSizeI.Reset;
+begin
+  FHandle.w := 0;
+  FHandle.h := 0;
+end;
+
+{ TBLBoxI }
+
+function BLBoxI: TBLBoxI; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLBoxI(const AX0, AY0, AX1, AY1: Integer): TBLBoxI; overload; inline;
+begin
+  Result.Reset(AX0, AY0, AX1, AY1);
+end;
+
+function TBLBoxI.Contains(const AX, AY: Integer): Boolean;
+begin
+  Result := (AX >= FHandle.x0) and (AY >= FHandle.y0)
+        and (AX <  FHandle.x1) and (AY <  FHandle.y1);
+end;
+
+function TBLBoxI.Contains(const AP: TBLPointI): Boolean;
+begin
+  Result := (AP.FHandle.x >= FHandle.x0) and (AP.FHandle.y >= FHandle.y0)
+        and (AP.FHandle.x <  FHandle.x1) and (AP.FHandle.y <  FHandle.y1);
+end;
+
+class operator TBLBoxI.Equal(const ALeft, ARight: TBLBoxI): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLBoxI.Equals(const AOther: TBLBoxI): Boolean;
+begin
+  Result := (FHandle.x0 = AOther.FHandle.x0)
+        and (FHandle.y0 = AOther.FHandle.y0)
+        and (FHandle.x1 = AOther.FHandle.x1)
+        and (FHandle.y1 = AOther.FHandle.y0);
+end;
+
+function TBLBoxI.GetHeight: Integer;
+begin
+  Result := FHandle.y1 - FHandle.y0;
+end;
+
+function TBLBoxI.GetWidth: Integer;
+begin
+  Result := FHandle.x1 - FHandle.y0;
+end;
+
+class operator TBLBoxI.NotEqual(const ALeft, ARight: TBLBoxI): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLBoxI.Reset(const AX0, AY0, AX1, AY1: Integer);
+begin
+  FHandle.x0 := AX0;
+  FHandle.y0 := AY0;
+  FHandle.x1 := AX1;
+  FHandle.y1 := AY1;
+end;
+
+procedure TBLBoxI.Reset;
+begin
+  FHandle.x0 := 0;
+  FHandle.y0 := 0;
+  FHandle.x1 := 0;
+  FHandle.y1 := 0;
+end;
+
+procedure TBLBoxI.SetHeight(const AValue: Integer);
+begin
+  FHandle.y1 := FHandle.y0 + AValue;
+end;
+
+procedure TBLBoxI.SetWidth(const AValue: Integer);
+begin
+  FHandle.x1 := FHandle.x0 + AValue;
+end;
+
+{ TBLRectI }
+
+function BLRectI: TBLRectI; inline;
+begin
+  Result.Reset;
+end;
+
+function BLRectI(const AX, AY, AW, AH: Integer): TBLRectI; inline;
+begin
+  Result.Reset(AX, AY, AW, AH);
+end;
+
+class operator TBLRectI.Equal(const ALeft, ARight: TBLRectI): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLRectI.Equals(const AOther: TBLRectI): Boolean;
+begin
+  Result := (FHandle.x = AOther.FHandle.x)
+        and (FHandle.y = AOther.FHandle.y)
+        and (FHandle.w = AOther.FHandle.w)
+        and (FHandle.h = AOther.FHandle.h);
+end;
+
+class operator TBLRectI.NotEqual(const ALeft, ARight: TBLRectI): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLRectI.Reset(const AX, AY, AW, AH: Integer);
+begin
+  FHandle.x := AX;
+  FHandle.y := AY;
+  FHandle.w := AW;
+  FHandle.h := AH;
+end;
+
+procedure TBLRectI.Reset;
+begin
+  FHandle.x := 0;
+  FHandle.y := 0;
+  FHandle.w := 0;
+  FHandle.h := 0;
+end;
+
+{ TBLPoint }
+
+function BLPoint: TBLPoint; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLPoint(const AX, AY: Double): TBLPoint; inline;
+begin
+  Result.Reset(AX, AY);
+end;
+
+class operator TBLPoint.Add(const ALeft, ARight: TBLPoint): TBLPoint;
+begin
+  Result.Reset(ALeft.FHandle.x + ARight.FHandle.x, ALeft.FHandle.y + ARight.FHandle.y);
+end;
+
+class operator TBLPoint.Divide(const ALeft: TBLPoint;
+  const ARight: Double): TBLPoint;
+begin
+  Result.Reset(ALeft.FHandle.x / ARight, ALeft.FHandle.y / ARight);
+end;
+
+class operator TBLPoint.Divide(const ALeft: Double;
+  const ARight: TBLPoint): TBLPoint;
+begin
+  Result.Reset(ALeft / ARight.FHandle.x, ALeft / ARight.FHandle.y);
+end;
+
+class operator TBLPoint.Divide(const ALeft, ARight: TBLPoint): TBLPoint;
+begin
+  Result.Reset(ALeft.FHandle.x / ARight.FHandle.x, ALeft.FHandle.y / ARight.FHandle.y);
+end;
+
+class operator TBLPoint.Add(const ALeft: Double;
+  const ARight: TBLPoint): TBLPoint;
+begin
+  Result.Reset(ALeft + ARight.FHandle.x, ALeft + ARight.FHandle.y);
+end;
+
+class operator TBLPoint.Add(const ALeft: TBLPoint;
+  const ARight: Double): TBLPoint;
+begin
+  Result.Reset(ALeft.FHandle.x + ARight, ALeft.FHandle.y + ARight);
+end;
+
+class operator TBLPoint.Equal(const ALeft, ARight: TBLPoint): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLPoint.Equals(const AOther: TBLPoint): Boolean;
+begin
+  Result := (FHandle.x = AOther.FHandle.x)
+        and (FHandle.y = AOther.FHandle.y);
+end;
+
+class operator TBLPoint.Multiply(const ALeft, ARight: TBLPoint): TBLPoint;
+begin
+  Result.Reset(ALeft.FHandle.x * ARight.FHandle.x, ALeft.FHandle.y * ARight.FHandle.y);
+end;
+
+class operator TBLPoint.Multiply(const ALeft: Double;
+  const ARight: TBLPoint): TBLPoint;
+begin
+  Result.Reset(ALeft * ARight.FHandle.x, ALeft * ARight.FHandle.y);
+end;
+
+class operator TBLPoint.Multiply(const ALeft: TBLPoint;
+  const ARight: Double): TBLPoint;
+begin
+  Result.Reset(ALeft.FHandle.x * ARight, ALeft.FHandle.y * ARight);
+end;
+
+class operator TBLPoint.Negative(const AValue: TBLPoint): TBLPoint;
+begin
+  Result.Reset(-AValue.FHandle.x, -AValue.FHandle.y);
+end;
+
+class operator TBLPoint.NotEqual(const ALeft, ARight: TBLPoint): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLPoint.Reset(const AX, AY: Double);
+begin
+  FHandle.x := AX;
+  FHandle.y := AY;
+end;
+
+class operator TBLPoint.Subtract(const ALeft: TBLPoint;
+  const ARight: Double): TBLPoint;
+begin
+  Result.Reset(ALeft.FHandle.x - ARight, ALeft.FHandle.y - ARight);
+end;
+
+class operator TBLPoint.Subtract(const ALeft: Double;
+  const ARight: TBLPoint): TBLPoint;
+begin
+  Result.Reset(ALeft - ARight.FHandle.x, ALeft - ARight.FHandle.y);
+end;
+
+class operator TBLPoint.Subtract(const ALeft, ARight: TBLPoint): TBLPoint;
+begin
+  Result.Reset(ALeft.FHandle.x - ARight.FHandle.x, ALeft.FHandle.y - ARight.FHandle.y);
+end;
+
+procedure TBLPoint.Reset;
+begin
+  FHandle.x := 0;
+  FHandle.y := 0;
+end;
+
+{ TBLSize }
+
+function BLSize: TBLSize; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLSize(const AW, AH: Double): TBLSize; overload; inline;
+begin
+  Result.Reset(AW, AH);
+end;
+
+class operator TBLSize.Equal(const ALeft, ARight: TBLSize): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLSize.Equals(const AOther: TBLSize): Boolean;
+begin
+  Result := (FHandle.w = AOther.FHandle.w)
+        and (FHandle.h = AOther.FHandle.h);
+end;
+
+class operator TBLSize.NotEqual(const ALeft, ARight: TBLSize): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLSize.Reset(const AW, AH: Double);
+begin
+  FHandle.w := AW;
+  FHandle.h := AH;
+end;
+
+procedure TBLSize.Reset;
+begin
+  FHandle.w := 0;
+  FHandle.h := 0;
+end;
+
+{ TBLBox }
+
+function BLBox: TBLBox; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLBox(const AX0, AY0, AX1, AY1: Double): TBLBox; inline;
+begin
+  Result.Reset(AX0, AY0, AX1, AY1);
+end;
+
+function TBLBox.Contains(const AX, AY: Double): Boolean;
+begin
+  Result := (AX >= FHandle.x0) and (AY >= FHandle.y0)
+        and (AX <  FHandle.x1) and (AY <  FHandle.y1);
+end;
+
+class operator TBLBox.Add(const ALeft: TBLPoint; const ARight: TBLBox): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x + ARight.FHandle.x0,
+               ALeft.FHandle.y + ARight.FHandle.y0,
+               ALeft.FHandle.x + ARight.FHandle.x1,
+               ALeft.FHandle.y + ARight.FHandle.y1);
+end;
+
+class operator TBLBox.Add(const ALeft: TBLBox; const ARight: TBLPoint): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x0 + ARight.FHandle.x,
+               ALeft.FHandle.y0 + ARight.FHandle.y,
+               ALeft.FHandle.x1 + ARight.FHandle.x,
+               ALeft.FHandle.y1 + ARight.FHandle.y);
+end;
+
+class operator TBLBox.Add(const ALeft: Double; const ARight: TBLBox): TBLBox;
+begin
+  Result.Reset(ALeft + ARight.FHandle.x0,
+               ALeft + ARight.FHandle.y0,
+               ALeft + ARight.FHandle.x1,
+               ALeft + ARight.FHandle.y1);
+end;
+
+class operator TBLBox.Add(const ALeft: TBLBox; const ARight: Double): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x0 + ARight,
+               ALeft.FHandle.y0 + ARight,
+               ALeft.FHandle.x1 + ARight,
+               ALeft.FHandle.y1 + ARight);
+end;
+
+function TBLBox.Contains(const AP: TBLPoint): Boolean;
+begin
+  Result := (AP.FHandle.x >= FHandle.x0) and (AP.FHandle.y >= FHandle.y0)
+        and (AP.FHandle.x <  FHandle.x1) and (AP.FHandle.y <  FHandle.y1);
+end;
+
+class operator TBLBox.Divide(const ALeft: TBLPoint;
+  const ARight: TBLBox): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x / ARight.FHandle.x0,
+               ALeft.FHandle.y / ARight.FHandle.y0,
+               ALeft.FHandle.x / ARight.FHandle.x1,
+               ALeft.FHandle.y / ARight.FHandle.y1);
+end;
+
+class operator TBLBox.Divide(const ALeft: TBLBox;
+  const ARight: TBLPoint): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x0 / ARight.FHandle.x,
+               ALeft.FHandle.y0 / ARight.FHandle.y,
+               ALeft.FHandle.x1 / ARight.FHandle.x,
+               ALeft.FHandle.y1 / ARight.FHandle.y);
+end;
+
+class operator TBLBox.Divide(const ALeft: Double; const ARight: TBLBox): TBLBox;
+begin
+  Result.Reset(ALeft / ARight.FHandle.x0,
+               ALeft / ARight.FHandle.y0,
+               ALeft / ARight.FHandle.x1,
+               ALeft / ARight.FHandle.y1);
+end;
+
+class operator TBLBox.Divide(const ALeft: TBLBox; const ARight: Double): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x0 / ARight,
+               ALeft.FHandle.y0 / ARight,
+               ALeft.FHandle.x1 / ARight,
+               ALeft.FHandle.y1 / ARight);
+end;
+
+class operator TBLBox.Equal(const ALeft, ARight: TBLBox): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLBox.Equals(const AOther: TBLBox): Boolean;
+begin
+  Result := (FHandle.x0 = AOther.FHandle.x0)
+        and (FHandle.y0 = AOther.FHandle.y0)
+        and (FHandle.x1 = AOther.FHandle.x1)
+        and (FHandle.y1 = AOther.FHandle.y0);
+end;
+
+function TBLBox.GetHeight: Double;
+begin
+  Result := FHandle.y1 - FHandle.y0;
+end;
+
+function TBLBox.GetWidth: Double;
+begin
+  Result := FHandle.x1 - FHandle.x0;
+end;
+
+class operator TBLBox.Multiply(const ALeft: TBLPoint;
+  const ARight: TBLBox): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x * ARight.FHandle.x0,
+               ALeft.FHandle.y * ARight.FHandle.y0,
+               ALeft.FHandle.x * ARight.FHandle.x1,
+               ALeft.FHandle.y * ARight.FHandle.y1);
+end;
+
+class operator TBLBox.Multiply(const ALeft: TBLBox;
+  const ARight: TBLPoint): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x0 * ARight.FHandle.x,
+               ALeft.FHandle.y0 * ARight.FHandle.y,
+               ALeft.FHandle.x1 * ARight.FHandle.x,
+               ALeft.FHandle.y1 * ARight.FHandle.y);
+end;
+
+class operator TBLBox.Multiply(const ALeft: Double;
+  const ARight: TBLBox): TBLBox;
+begin
+  Result.Reset(ALeft * ARight.FHandle.x0,
+               ALeft * ARight.FHandle.y0,
+               ALeft * ARight.FHandle.x1,
+               ALeft * ARight.FHandle.y1);
+end;
+
+class operator TBLBox.Multiply(const ALeft: TBLBox;
+  const ARight: Double): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x0 * ARight,
+               ALeft.FHandle.y0 * ARight,
+               ALeft.FHandle.x1 * ARight,
+               ALeft.FHandle.y1 * ARight);
+end;
+
+class operator TBLBox.NotEqual(const ALeft, ARight: TBLBox): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLBox.Reset;
+begin
+  FHandle.x0 := 0;
+  FHandle.y0 := 0;
+  FHandle.x1 := 0;
+  FHandle.y1 := 0;
+end;
+
+procedure TBLBox.Reset(const AX0, AY0, AX1, AY1: Double);
+begin
+  FHandle.x0 := AX0;
+  FHandle.y0 := AY0;
+  FHandle.x1 := AX1;
+  FHandle.y1 := AY1;
+end;
+
+procedure TBLBox.SetHeight(const AValue: Double);
+begin
+  FHandle.y1 := FHandle.y0 + AValue;
+end;
+
+procedure TBLBox.SetWidth(const AValue: Double);
+begin
+  FHandle.x1 := FHandle.x0 + AValue;
+end;
+
+class operator TBLBox.Subtract(const ALeft: TBLPoint;
+  const ARight: TBLBox): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x - ARight.FHandle.x0,
+               ALeft.FHandle.y - ARight.FHandle.y0,
+               ALeft.FHandle.x - ARight.FHandle.x1,
+               ALeft.FHandle.y - ARight.FHandle.y1);
+end;
+
+class operator TBLBox.Subtract(const ALeft: TBLBox;
+  const ARight: TBLPoint): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x0 - ARight.FHandle.x,
+               ALeft.FHandle.y0 - ARight.FHandle.y,
+               ALeft.FHandle.x1 - ARight.FHandle.x,
+               ALeft.FHandle.y1 - ARight.FHandle.y);
+end;
+
+class operator TBLBox.Subtract(const ALeft: Double;
+  const ARight: TBLBox): TBLBox;
+begin
+  Result.Reset(ALeft - ARight.FHandle.x0,
+               ALeft - ARight.FHandle.y0,
+               ALeft - ARight.FHandle.x1,
+               ALeft - ARight.FHandle.y1);
+end;
+
+class operator TBLBox.Subtract(const ALeft: TBLBox;
+  const ARight: Double): TBLBox;
+begin
+  Result.Reset(ALeft.FHandle.x0 - ARight,
+               ALeft.FHandle.y0 - ARight,
+               ALeft.FHandle.x1 - ARight,
+               ALeft.FHandle.y1 - ARight);
+end;
+
+{ TBLRect }
+
+function BLRect: TBLRect; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLRect(const AX, AY, AW, AH: Double): TBLRect; inline;
+begin
+  Result.Reset(AX, AY, AW, AH);
+end;
+
+class operator TBLRect.Equal(const ALeft, ARight: TBLRect): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLRect.Equals(const AOther: TBLRect): Boolean;
+begin
+  Result := (FHandle.x = AOther.FHandle.x)
+        and (FHandle.y = AOther.FHandle.y)
+        and (FHandle.w = AOther.FHandle.w)
+        and (FHandle.h = AOther.FHandle.h);
+end;
+
+class operator TBLRect.NotEqual(const ALeft, ARight: TBLRect): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLRect.Reset(const AX, AY, AW, AH: Double);
+begin
+  FHandle.x := AX;
+  FHandle.y := AY;
+  FHandle.w := AW;
+  FHandle.h := AH;
+end;
+
+procedure TBLRect.Reset;
+begin
+  FHandle.x := 0;
+  FHandle.y := 0;
+  FHandle.w := 0;
+  FHandle.h := 0;
+end;
+
+{ TBLLine }
+
+function BLLine: TBLLine; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLLine(const AX0, AY0, AX1, AY1: Double): TBLLine; overload; inline;
+begin
+  Result.Reset(AX0, AY0, AX1, AY1);
+end;
+
+function BLLine(const AP0, AP1: TBLPoint): TBLLine; overload; inline;
+begin
+  Result.Reset(AP0, AP1);
+end;
+
+class operator TBLLine.Equal(const ALeft, ARight: TBLLine): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLLine.Equals(const AOther: TBLLine): Boolean;
+begin
+  Result := (FHandle.x0 = AOther.FHandle.x0)
+        and (FHandle.y0 = AOther.FHandle.y0)
+        and (FHandle.x1 = AOther.FHandle.x1)
+        and (FHandle.y1 = AOther.FHandle.y1);
+end;
+
+class operator TBLLine.NotEqual(const ALeft, ARight: TBLLine): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLLine.Reset(const AX0, AY0, AX1, AY1: Double);
+begin
+  FHandle.x0 := AX0;
+  FHandle.y0 := AY0;
+  FHandle.x1 := AX1;
+  FHandle.y1 := AY1;
+end;
+
+procedure TBLLine.Reset(const AP0, AP1: TBLPoint);
+begin
+  FHandle.x0 := AP0.FHandle.x;
+  FHandle.y0 := AP0.FHandle.y;
+  FHandle.x1 := AP1.FHandle.x;
+  FHandle.y1 := AP1.FHandle.y;
+end;
+
+procedure TBLLine.Reset;
+begin
+  FHandle.x0 := 0;
+  FHandle.y0 := 0;
+  FHandle.x1 := 0;
+  FHandle.y1 := 0;
+end;
+
+{ TBLTriangle }
+
+function BLTriangle: TBLTriangle; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLTriangle(const AX0, AY0, AX1, AY1, AX2, AY2: Double): TBLTriangle; inline;
+begin
+  Result.Reset(AX0, AY0, AX1, AY1, AX2, AY2);
+end;
+
+class operator TBLTriangle.Equal(const ALeft, ARight: TBLTriangle): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLTriangle.Equals(const AOther: TBLTriangle): Boolean;
+begin
+  Result := (FHandle.x0 = AOther.FHandle.x0)
+        and (FHandle.y0 = AOther.FHandle.y0)
+        and (FHandle.x1 = AOther.FHandle.x1)
+        and (FHandle.y1 = AOther.FHandle.y1)
+        and (FHandle.x2 = AOther.FHandle.x2)
+        and (FHandle.y2 = AOther.FHandle.y2);
+end;
+
+class operator TBLTriangle.NotEqual(const ALeft, ARight: TBLTriangle): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLTriangle.Reset(const AX0, AY0, AX1, AY1, AX2, AY2: Double);
+begin
+  FHandle.x0 := AX0;
+  FHandle.y0 := AY0;
+  FHandle.x1 := AX1;
+  FHandle.y1 := AY1;
+  FHandle.x2 := AX2;
+  FHandle.y2 := AY2;
+end;
+
+procedure TBLTriangle.Reset;
+begin
+  FHandle.x0 := 0;
+  FHandle.y0 := 0;
+  FHandle.x1 := 0;
+  FHandle.y1 := 0;
+  FHandle.x2 := 0;
+  FHandle.y2 := 0;
+end;
+
+{ TBLRoundRect }
+
+function BLRoundRect: TBLRoundRect; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLRoundRect(const ARect: TBLRect; const AR: Double): TBLRoundRect; overload; inline;
+begin
+  Result.Reset(ARect, AR);
+end;
+
+function BLRoundRect(const ARect: TBLRect; const ARX, ARY: Double): TBLRoundRect; overload; inline;
+begin
+  Result.Reset(ARect, ARX, ARY);
+end;
+
+function BLRoundRect(const AX, AY, AW, AH, AR: Double): TBLRoundRect; overload; inline;
+begin
+  Result.Reset(AX, AY, AW, AH, AR);
+end;
+
+function BLRoundRect(const AX, AY, AW, AH, ARX, ARY: Double): TBLRoundRect; overload; inline;
+begin
+  Result.Reset(AX, AY, AW, AH, ARX, ARY);
+end;
+
+class operator TBLRoundRect.Equal(const ALeft, ARight: TBLRoundRect): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLRoundRect.Equals(const AOther: TBLRoundRect): Boolean;
+begin
+  Result := (FHandle.x = AOther.FHandle.x)
+        and (FHandle.y = AOther.FHandle.y)
+        and (FHandle.w = AOther.FHandle.w)
+        and (FHandle.h = AOther.FHandle.h)
+        and (FHandle.rx = AOther.FHandle.rx)
+        and (FHandle.ry = AOther.FHandle.ry);
+end;
+
+class operator TBLRoundRect.NotEqual(const ALeft,
+  ARight: TBLRoundRect): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLRoundRect.Reset(const ARect: TBLRect; const AR: Double);
+begin
+  FHandle.x := ARect.FHandle.x;
+  FHandle.y := ARect.FHandle.y;
+  FHandle.w := ARect.FHandle.w;
+  FHandle.h := ARect.FHandle.h;
+  FHandle.rx := AR;
+  FHandle.ry := AR;
+end;
+
+procedure TBLRoundRect.Reset(const AX, AY, AW, AH, AR: Double);
+begin
+  FHandle.x := AX;
+  FHandle.y := AY;
+  FHandle.w := AW;
+  FHandle.h := AH;
+  FHandle.rx := AR;
+  FHandle.ry := AR;
+end;
+
+procedure TBLRoundRect.Reset(const AX, AY, AW, AH, ARX, ARY: Double);
+begin
+  FHandle.x := AX;
+  FHandle.y := AY;
+  FHandle.w := AW;
+  FHandle.h := AH;
+  FHandle.rx := ARX;
+  FHandle.ry := ARY;
+end;
+
+procedure TBLRoundRect.Reset(const ARect: TBLRect; const ARX, ARY: Double);
+begin
+  FHandle.x := ARect.FHandle.x;
+  FHandle.y := ARect.FHandle.y;
+  FHandle.w := ARect.FHandle.w;
+  FHandle.h := ARect.FHandle.h;
+  FHandle.rx := ARX;
+  FHandle.ry := ARY;
+end;
+
+procedure TBLRoundRect.Reset;
+begin
+  FHandle.x := 0;
+  FHandle.y := 0;
+  FHandle.w := 0;
+  FHandle.h := 0;
+  FHandle.rx := 0;
+  FHandle.ry := 0;
+end;
+
+{ TBLCircle }
+
+function BLCircle: TBLCircle; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLCircle(const ACX, ACY, AR: Double): TBLCircle; inline;
+begin
+  Result.Reset(ACX, ACY, AR);
+end;
+
+class operator TBLCircle.Equal(const ALeft, ARight: TBLCircle): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLCircle.Equals(const AOther: TBLCircle): Boolean;
+begin
+  Result := (FHandle.cx = AOther.FHandle.cx)
+        and (FHandle.cy = AOther.FHandle.cy)
+        and (FHandle.r = AOther.FHandle.r);
+end;
+
+class operator TBLCircle.NotEqual(const ALeft, ARight: TBLCircle): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLCircle.Reset(const ACX, ACY, AR: Double);
+begin
+  FHandle.cx := ACX;
+  FHandle.cy := ACY;
+  FHandle.r := AR;
+end;
+
+procedure TBLCircle.Reset;
+begin
+  FHandle.cx := 0;
+  FHandle.cy := 0;
+  FHandle.r := 0;
+end;
+
+{ TBLEllipse }
+
+function BLEllipse: TBLEllipse; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLEllipse(const ACX, ACY, ARX, ARY: Double): TBLEllipse; inline;
+begin
+  Result.Reset(ACX, ACY, ARX, ARY);
+end;
+
+class operator TBLEllipse.Equal(const ALeft, ARight: TBLEllipse): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLEllipse.Equals(const AOther: TBLEllipse): Boolean;
+begin
+  Result := (FHandle.cx = AOther.FHandle.cx)
+        and (FHandle.cy = AOther.FHandle.cy)
+        and (FHandle.rx = AOther.FHandle.rx)
+        and (FHandle.ry = AOther.FHandle.ry);
+end;
+
+class operator TBLEllipse.NotEqual(const ALeft, ARight: TBLEllipse): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLEllipse.Reset(const ACX, ACY, ARX, ARY: Double);
+begin
+  FHandle.cx := ACX;
+  FHandle.cy := ACY;
+  FHandle.rx := ARX;
+  FHandle.ry := ARY;
+end;
+
+procedure TBLEllipse.Reset;
+begin
+  FHandle.cx := 0;
+  FHandle.cy := 0;
+  FHandle.rx := 0;
+  FHandle.ry := 0;
+end;
+
+{ TBLArc }
+
+function BLArc: TBLArc; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLArc(const ACX, ACY, AR, AStart, ASweep: Double): TBLArc; overload; inline;
+begin
+  Result.Reset(ACX, ACY, AR, AStart, ASweep);
+end;
+
+function BLArc(const ACX, ACY, ARX, ARY, AStart, ASweep: Double): TBLArc; overload; inline;
+begin
+  Result.Reset(ACX, ACY, ARX, ARY, AStart, ASweep);
+end;
+
+class operator TBLArc.Equal(const ALeft, ARight: TBLArc): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLArc.Equals(const AOther: TBLArc): Boolean;
+begin
+  Result := (FHandle.cx = AOther.FHandle.cx)
+        and (FHandle.cy = AOther.FHandle.cy)
+        and (FHandle.rx = AOther.FHandle.rx)
+        and (FHandle.ry = AOther.FHandle.ry)
+        and (FHandle.start = AOther.FHandle.start)
+        and (FHandle.sweep = AOther.FHandle.sweep);
+end;
+
+class operator TBLArc.NotEqual(const ALeft, ARight: TBLArc): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLArc.Reset(const ACX, ACY, ARX, ARY, AStart, ASweep: Double);
+begin
+  FHandle.cx := ACX;
+  FHandle.cy := ACY;
+  FHandle.rx := ARX;
+  FHandle.ry := ARY;
+  FHandle.start := AStart;
+  FHandle.sweep := ASweep;
+end;
+
+procedure TBLArc.Reset(const ACX, ACY, AR, AStart, ASweep: Double);
+begin
+  FHandle.cx := ACX;
+  FHandle.cy := ACY;
+  FHandle.rx := AR;
+  FHandle.ry := AR;
+  FHandle.start := AStart;
+  FHandle.sweep := ASweep;
+end;
+
+procedure TBLArc.Reset;
+begin
+  FHandle.cx := 0;
+  FHandle.cy := 0;
+  FHandle.rx := 0;
+  FHandle.ry := 0;
+  FHandle.start := 0;
+  FHandle.sweep := 0;
+end;
+
+{ Globals }
+
+function BLAbs(const AA: TBLPoint): TBLPoint; overload; inline;
+begin
+  Result.Reset(Abs(AA.FHandle.x), Abs(AA.FHandle.y));
+end;
+
+function BLAbs(const AA: TBLSize): TBLSize; overload; inline;
+begin
+  Result.Reset(Abs(AA.FHandle.w), Abs(AA.FHandle.h));
+end;
+
+function BLMin(const AA, AB: TBLPoint): TBLPoint; overload; inline;
+begin
+  Result.Reset(Min(AA.FHandle.x, AB.FHandle.x), Min(AA.FHandle.y, AB.FHandle.y));
+end;
+
+function BLMin(const AA: TBLPoint; const AB: Double): TBLPoint; overload; inline;
+begin
+  Result.Reset(Min(AA.FHandle.x, AB), Min(AA.FHandle.y, AB));
+end;
+
+function BLMin(const AA: Double; const AB: TBLPoint): TBLPoint; overload; inline;
+begin
+  Result.Reset(Min(AA, AB.FHandle.x), Min(AA, AB.FHandle.y));
+end;
+
+function BLMin(const AA, AB: TBLSize): TBLSize; overload; inline;
+begin
+  Result.Reset(Min(AA.FHandle.w, AB.FHandle.w), Min(AA.FHandle.h, AB.FHandle.h));
+end;
+
+function BLMax(const AA, AB: TBLPoint): TBLPoint; overload; inline;
+begin
+  Result.Reset(Max(AA.FHandle.x, AB.FHandle.x), Max(AA.FHandle.y, AB.FHandle.y));
+end;
+
+function BLMax(const AA: TBLPoint; const AB: Double): TBLPoint; overload; inline;
+begin
+  Result.Reset(Max(AA.FHandle.x, AB), Max(AA.FHandle.y, AB));
+end;
+
+function BLMax(const AA: Double; const AB: TBLPoint): TBLPoint; overload; inline;
+begin
+  Result.Reset(Max(AA, AB.FHandle.x), Max(AA, AB.FHandle.y));
+end;
+
+function BLMax(const AA, AB: TBLSize): TBLSize; overload; inline;
+begin
+  Result.Reset(Max(AA.FHandle.w, AB.FHandle.w), Max(AA.FHandle.h, AB.FHandle.h));
+end;
+
+function BLClamp(const AA: TBLPoint; const AB, AC: Double): TBLPoint; inline;
+begin
+  Result := BLMin(AC, BLMax(AA, AB));
+end;
+
+{$ENDREGION 'Geometry'}
+
+{$REGION 'Matrix'}
+
+{ TBLMatrix2D }
+
+function BLMatrix2D: TBLMatrix2D; overload; inline;
+begin
+  Result.Reset;
+end;
+
+function BLMatrix2D(const AM00, AM01, AM10, AM11, AM20, AM21: Double): TBLMatrix2D; overload; inline;
+begin
+  Result.Reset(AM00, AM01, AM10, AM11, AM20, AM21);
+end;
+
+class operator TBLMatrix2D.Equal(const ALeft, ARight: TBLMatrix2D): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLMatrix2D.Equals(const AOther: TBLMatrix2D): Boolean;
+begin
+  Result := (FHandle.m00 = AOther.FHandle.m00)
+        and (FHandle.m01 = AOther.FHandle.m01)
+        and (FHandle.m10 = AOther.FHandle.m10)
+        and (FHandle.m11 = AOther.FHandle.m11)
+        and (FHandle.m20 = AOther.FHandle.m20)
+        and (FHandle.m21 = AOther.FHandle.m21);
+end;
+
+function TBLMatrix2D.GetDeterminant: Double;
+begin
+  Result := (FHandle.m00 * FHandle.m11) - (FHandle.m01 * FHandle.m10);
+end;
+
+function TBLMatrix2D.GetElement(const AIndex: TBLMatrix2DValue): Double;
+begin
+  Result := FHandle.m[Ord(AIndex)];
+end;
+
+function TBLMatrix2D.GetMatrixType: TBLMatrix2DType;
+begin
+  Result := TBLMatrix2DType(blMatrix2DGetType(@FHandle));
+end;
+
+class function TBLMatrix2D.Invert(const ASrc: TBLMatrix2D;
+  out ADst: TBLMatrix2D): Boolean;
+begin
+  Result := (blMatrix2DInvert(@ADst.FHandle, @ASrc.FHandle) = BL_SUCCESS);
+end;
+
+function TBLMatrix2D.Invert: Boolean;
+begin
+  Result := (blMatrix2DInvert(@FHandle, @FHandle) = BL_SUCCESS);
+end;
+
+class function TBLMatrix2D.MakeIdentity: TBLMatrix2D;
+begin
+  Result.Reset(1, 0, 0, 1, 0, 0);
+end;
+
+class function TBLMatrix2D.MakeRotation(const AAngle, AX,
+  AY: Double): TBLMatrix2D;
+begin
+  Result.ResetToRotation(AAngle, AX, AY);
+end;
+
+class function TBLMatrix2D.MakeRotation(const AAngle: Double): TBLMatrix2D;
+begin
+  Result.ResetToRotation(AAngle, 0, 0);
+end;
+
+class function TBLMatrix2D.MakeRotation(const AAngle: Double;
+  const AP: TBLPoint): TBLMatrix2D;
+begin
+  Result.ResetToRotation(AAngle, AP.FHandle.x, AP.FHandle.y);
+end;
+
+class function TBLMatrix2D.MakeScaling(const AX, AY: Double): TBLMatrix2D;
+begin
+  Result.Reset(AX, 0, 0, AY, 0, 0);
+end;
+
+class function TBLMatrix2D.MakeScaling(const AP: TBLPoint): TBLMatrix2D;
+begin
+  Result.Reset(AP.FHandle.x, 0, 0, AP.FHandle.y, 0, 0);
+end;
+
+class function TBLMatrix2D.MakeScaling(const AP: TBLPointI): TBLMatrix2D;
+begin
+  Result.Reset(AP.FHandle.x, 0, 0, AP.FHandle.y, 0, 0);
+end;
+
+class function TBLMatrix2D.MakeScaling(const AXY: Double): TBLMatrix2D;
+begin
+  Result.Reset(AXY, 0, 0, AXY, 0, 0);
+end;
+
+class function TBLMatrix2D.MakeSinCos(const ASin, ACos: Double;
+  const ATranslate: TBLPoint): TBLMatrix2D;
+begin
+  Result.Reset(ACos, ASin, -ASin, ACos, ATranslate.FHandle.x, ATranslate.FHandle.y);
+end;
+
+class function TBLMatrix2D.MakeSinCos(const ASin, ACos, ATranslateX,
+  ATranslateY: Double): TBLMatrix2D;
+begin
+  Result.Reset(ACos, ASin, -ASin, ACos, ATranslateX, ATranslateY);
+end;
+
+class function TBLMatrix2D.MakeSkewing(const AX, AY: Double): TBLMatrix2D;
+begin
+  Result.ResetToSkewing(AX, AY);
+end;
+
+class function TBLMatrix2D.MakeSkewing(const AP: TBLPoint): TBLMatrix2D;
+begin
+  Result.ResetToSkewing(AP.FHandle.x, AP.FHandle.y);
+end;
+
+class function TBLMatrix2D.MakeTranslation(const AP: TBLPointI): TBLMatrix2D;
+begin
+  Result.Reset(1, 0, 0, 1, AP.FHandle.x, AP.FHandle.y);
+end;
+
+class function TBLMatrix2D.MakeTranslation(const AP: TBLPoint): TBLMatrix2D;
+begin
+  Result.Reset(1, 0, 0, 1, AP.FHandle.x, AP.FHandle.y);
+end;
+
+class function TBLMatrix2D.MakeTranslation(const AX, AY: Double): TBLMatrix2D;
+begin
+  Result.Reset(1, 0, 0, 1, AX, AY);
+end;
+
+function TBLMatrix2D.MapPoint(const AP: TBLPoint): TBLPoint;
+begin
+  Result.Reset(
+    (AP.FHandle.x * FHandle.m00) + (AP.FHandle.y * FHandle.m10) + FHandle.m20,
+    (AP.FHandle.x * FHandle.m01) + (AP.FHandle.y * FHandle.m11) + FHandle.m21);
+end;
+
+function TBLMatrix2D.MapPoint(const AX, AY: Double): TBLPoint;
+begin
+  Result.Reset(
+    (AX * FHandle.m00) + (AY * FHandle.m10) + FHandle.m20,
+    (AX * FHandle.m01) + (AY * FHandle.m11) + FHandle.m21);
+end;
+
+function TBLMatrix2D.MapVector(const AX, AY: Double): TBLPoint;
+begin
+  Result.Reset(
+    (AX * FHandle.m00) + (AY * FHandle.m10),
+    (AX * FHandle.m01) + (AY * FHandle.m11));
+end;
+
+function TBLMatrix2D.MapVector(const AV: TBLPoint): TBLPoint;
+begin
+  Result.Reset(
+    (AV.FHandle.x * FHandle.m00) + (AV.FHandle.y * FHandle.m10),
+    (AV.FHandle.x * FHandle.m01) + (AV.FHandle.y * FHandle.m11));
+end;
+
+class operator TBLMatrix2D.NotEqual(const ALeft, ARight: TBLMatrix2D): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLMatrix2D.PostRotate(const AAngle, AX, AY: Double);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AX;
+  Data[2] := AY;
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLMatrix2D.PostRotate(const AAngle: Double; const AP: TBLPoint);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLMatrix2D.PostRotate(const AAngle: Double);
+begin
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE, @AAngle));
+end;
+
+procedure TBLMatrix2D.PostScale(const AP: TBLPoint);
+begin
+  PostScale(AP.FHandle.x, AP.FHandle.y);
+end;
+
+procedure TBLMatrix2D.PostScale(const AX, AY: Double);
+begin
+  FHandle.m00 := FHandle.m00 * AX;
+  FHandle.m01 := FHandle.m01 * AY;
+  FHandle.m10 := FHandle.m10 * AX;
+  FHandle.m11 := FHandle.m11 * AY;
+  FHandle.m20 := FHandle.m10 * AX;
+  FHandle.m21 := FHandle.m11 * AY;
+end;
+
+procedure TBLMatrix2D.PostScale(const AXY: Double);
+begin
+  PostScale(AXY, AXY);
+end;
+
+procedure TBLMatrix2D.PostScale(const AP: TBLPointI);
+begin
+  PostScale(AP.FHandle.x, AP.FHandle.y);
+end;
+
+procedure TBLMatrix2D.PostSkew(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_POST_SKEW, @Data));
+end;
+
+procedure TBLMatrix2D.PostSkew(const AP: TBLPoint);
+begin
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_POST_SKEW, @AP));
+end;
+
+procedure TBLMatrix2D.PostTransform(const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSFORM, @AMatrix));
+end;
+
+procedure TBLMatrix2D.PostTranslate(const AX, AY: Double);
+begin
+  FHandle.m20 := FHandle.m20 + AX;
+  FHandle.m21 := FHandle.m21 + AY;
+end;
+
+procedure TBLMatrix2D.PostTranslate(const AP: TBLPoint);
+begin
+  FHandle.m20 := FHandle.m20 + AP.FHandle.x;
+  FHandle.m21 := FHandle.m21 + AP.FHandle.y;
+end;
+
+procedure TBLMatrix2D.PostTranslate(const AP: TBLPointI);
+begin
+  FHandle.m20 := FHandle.m20 + AP.FHandle.x;
+  FHandle.m21 := FHandle.m21 + AP.FHandle.y;
+end;
+
+procedure TBLMatrix2D.Reset(const AM00, AM01, AM10, AM11, AM20, AM21: Double);
+begin
+  FHandle.m00 := AM00;
+  FHandle.m01 := AM01;
+  FHandle.m10 := AM10;
+  FHandle.m11 := AM11;
+  FHandle.m20 := AM20;
+  FHandle.m21 := AM21;
+end;
+
+procedure TBLMatrix2D.Reset;
+begin
+  FHandle.m00 := 1;
+  FHandle.m01 := 0;
+  FHandle.m10 := 0;
+  FHandle.m11 := 1;
+  FHandle.m20 := 0;
+  FHandle.m21 := 0;
+end;
+
+procedure TBLMatrix2D.ResetToRotation(const AAngle: Double);
+begin
+  _BLCheck(blMatrix2DSetRotation(@FHandle, AAngle, 0, 0));
+end;
+
+procedure TBLMatrix2D.ResetToRotation(const AAngle, AX, AY: Double);
+begin
+  _BLCheck(blMatrix2DSetRotation(@FHandle, AAngle, AX, AY));
+end;
+
+procedure TBLMatrix2D.ResetToRotation(const AAngle: Double; const AP: TBLPoint);
+begin
+  _BLCheck(blMatrix2DSetRotation(@FHandle, AAngle, AP.FHandle.x, AP.FHandle.y));
+end;
+
+procedure TBLMatrix2D.ResetToScaling(const AX, AY: Double);
+begin
+  Reset(AX, 0, 0, AY, 0, 0);
+end;
+
+procedure TBLMatrix2D.ResetToScaling(const AP: TBLPoint);
+begin
+  Reset(AP.FHandle.x, 0, 0, AP.FHandle.y, 0, 0);
+end;
+
+procedure TBLMatrix2D.ResetToScaling(const AXY: Double);
+begin
+  Reset(AXY, 0, 0, AXY, 0, 0);
+end;
+
+procedure TBLMatrix2D.ResetToScaling(const AP: TBLPointI);
+begin
+  Reset(AP.FHandle.x, 0, 0, AP.FHandle.y, 0, 0);
+end;
+
+procedure TBLMatrix2D.ResetToSinCos(const ASin, ACos, ATranslateX,
+  ATranslateY: Double);
+begin
+  Reset(ACos, ASin, -ASin, ACos, ATranslateX, ATranslateY);
+end;
+
+procedure TBLMatrix2D.ResetToSinCos(const ASin, ACos: Double;
+  const ATranslate: TBLPoint);
+begin
+  Reset(ACos, ASin, -ASin, ACos, ATranslate.FHandle.x, ATranslate.FHandle.y);
+end;
+
+procedure TBLMatrix2D.ResetToSkewing(const AP: TBLPoint);
+begin
+  _BLCheck(blMatrix2DSetSkewing(@FHandle, AP.FHandle.x, AP.FHandle.y));
+end;
+
+procedure TBLMatrix2D.ResetToSkewing(const AX, AY: Double);
+begin
+  _BLCheck(blMatrix2DSetSkewing(@FHandle, AX, AY));
+end;
+
+procedure TBLMatrix2D.ResetToTranslation(const AP: TBLPointI);
+begin
+  Reset(1, 0, 0, 1, AP.FHandle.x, AP.FHandle.y);
+end;
+
+procedure TBLMatrix2D.ResetToTranslation(const AP: TBLPoint);
+begin
+  Reset(1, 0, 0, 1, AP.FHandle.x, AP.FHandle.y);
+end;
+
+procedure TBLMatrix2D.ResetToTranslation(const AX, AY: Double);
+begin
+  Reset(1, 0, 0, 1, AX, AY);
+end;
+
+procedure TBLMatrix2D.Rotate(const AAngle: Double);
+begin
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_ROTATE, @AAngle));
+end;
+
+procedure TBLMatrix2D.Rotate(const AAngle: Double; const AP: TBLPoint);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLMatrix2D.Rotate(const AAngle, AX, AY: Double);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AX;
+  Data[2] := AY;
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLMatrix2D.Scale(const AXY: Double);
+begin
+  FHandle.m00 := FHandle.m00 * AXY;
+  FHandle.m01 := FHandle.m01 * AXY;
+  FHandle.m10 := FHandle.m10 * AXY;
+  FHandle.m11 := FHandle.m11 * AXY;
+end;
+
+procedure TBLMatrix2D.Scale(const AP: TBLPointI);
+begin
+  Scale(AP.FHandle.x, AP.FHandle.y);
+end;
+
+procedure TBLMatrix2D.Scale(const AP: TBLPoint);
+begin
+  Scale(AP.FHandle.x, AP.FHandle.y);
+end;
+
+procedure TBLMatrix2D.Scale(const AX, AY: Double);
+begin
+  FHandle.m00 := FHandle.m00 * AX;
+  FHandle.m01 := FHandle.m01 * AX;
+  FHandle.m10 := FHandle.m10 * AY;
+  FHandle.m11 := FHandle.m11 * AY;
+end;
+
+procedure TBLMatrix2D.SetElement(const AIndex: TBLMatrix2DValue;
+  const AValue: Double);
+begin
+  FHandle.m[Ord(AIndex)] := AValue;
+end;
+
+procedure TBLMatrix2D.Skew(const AP: TBLPoint);
+begin
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_SKEW, @AP));
+end;
+
+procedure TBLMatrix2D.Skew(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_SKEW, @Data));
+end;
+
+procedure TBLMatrix2D.Transform(const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blMatrix2DApplyOp(@FHandle, BL_MATRIX2D_OP_TRANSFORM, @AMatrix));
+end;
+
+procedure TBLMatrix2D.Translate(const AX, AY: Double);
+begin
+  FHandle.m20 := FHandle.m20 + (AX * FHandle.m00) + (AY * FHandle.m10);
+  FHandle.m21 := FHandle.m21 + (AX * FHandle.m01) + (AY * FHandle.m11);
+end;
+
+procedure TBLMatrix2D.Translate(const AP: TBLPoint);
+begin
+  Translate(AP.FHandle.x, AP.FHandle.y);
+end;
+
+procedure TBLMatrix2D.Translate(const AP: TBLPointI);
+begin
+  Translate(AP.FHandle.x, AP.FHandle.y);
+end;
+
+{$ENDREGION 'Matrix'}
+
+{$REGION 'Random'}
+
+{ TBLRandom }
+
+class operator TBLRandom.Equal(const ALeft, ARight: TBLRandom): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLRandom.Equals(const AOther: TBLRandom): Boolean;
+begin
+  Result := (FHandle.data[0] = AOther.FHandle.data[0])
+        and (FHandle.data[1] = AOther.FHandle.data[1]);
+end;
+
+function TBLRandom.NextDouble: Double;
+begin
+  Result := blRandomNextDouble(@FHandle);
+end;
+
+function TBLRandom.NextUInt32: UInt32;
+begin
+  Result := blRandomNextUInt32(@FHandle);
+end;
+
+function TBLRandom.NextUInt64: UInt64;
+begin
+  Result := blRandomNextUInt64(@FHandle);
+end;
+
+class operator TBLRandom.NotEqual(const ALeft, ARight: TBLRandom): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLRandom.Reset(const ASeed: UInt64);
+begin
+  blRandomReset(@FHandle, ASeed);
+end;
+
+{$ENDREGION 'Random'}
+
+{$REGION 'Gradient'}
+
+{ TBLGradientStop }
+
+function BLGradientStop(const AOffset: Double; const ARgba: TBLRgba32): TBLGradientStop; overload; inline;
+begin
+  Result.Reset(AOffset, ARgba);
+end;
+
+function BLGradientStop(const AOffset: Double; const ARgba: TBLRgba64): TBLGradientStop; overload; inline;
+begin
+  Result.Reset(AOffset, ARgba);
+end;
+
+class operator TBLGradientStop.Equal(const ALeft,
+  ARight: TBLGradientStop): Boolean;
+begin
+  Result := (ALeft.FHandle.offset = ARight.FHandle.offset)
+        and (ALeft.FHandle.rgba.value = ARight.FHandle.rgba.value);
+end;
+
+function TBLGradientStop.Equals(const AOther: TBLGradientStop): Boolean;
+begin
+  Result := (Self = AOther);
+end;
+
+function TBLGradientStop.GetRgba: TBLRgba64;
+begin
+  Result.FHandle.value := FHandle.rgba.value;
+end;
+
+class operator TBLGradientStop.NotEqual(const ALeft,
+  ARight: TBLGradientStop): Boolean;
+begin
+  Result := not (ALeft = ARight);
+end;
+
+procedure TBLGradientStop.Reset(const AOffset: Double; const ARgba: TBLRgba64);
+begin
+  FHandle.offset := AOffset;
+  FHandle.rgba.value := ARgba.FHandle.value;
+end;
+
+procedure TBLGradientStop.Reset(const AOffset: Double; const ARgba: TBLRgba32);
+begin
+  FHandle.offset := AOffset;
+  TBLRgba64(FHandle.rgba).Reset(ARgba);
+end;
+
+procedure TBLGradientStop.Reset;
+begin
+  FHandle.offset := 0;
+  FHandle.rgba.value := 0;
+end;
+
+procedure TBLGradientStop.SetRgba(const AValue: TBLRgba64);
+begin
+  FHandle.rgba.value := AValue.FHandle.value;
+end;
+
+{ TBLLinearGradientValues }
+
+function BLLinearGradientValues(const AX0, AY0, AX1, AY1: Double): TBLLinearGradientValues; inline;
+begin
+  Result.Reset(AX0, AY0, AX1, AY1);
+end;
+
+procedure TBLLinearGradientValues.Reset(const AX0, AY0, AX1, AY1: Double);
+begin
+  FHandle.x0 := AX0;
+  FHandle.y0 := AY0;
+  FHandle.x1 := AX1;
+  FHandle.y1 := AY1;
+end;
+
+procedure TBLLinearGradientValues.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+{ TBLRadialGradientValues }
+
+function BLRadialGradientValues(const AX0, AY0, AX1, AY1, AR0: Double): TBLRadialGradientValues; inline;
+begin
+  Result.Reset(AX0, AY0, AX1, AY1, AR0);
+end;
+
+procedure TBLRadialGradientValues.Reset(const AX0, AY0, AX1, AY1, AR0: Double);
+begin
+  FHandle.x0 := AX0;
+  FHandle.y0 := AY0;
+  FHandle.x1 := AX1;
+  FHandle.y1 := AY1;
+  FHandle.r0 := AR0;
+end;
+
+procedure TBLRadialGradientValues.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+{ TBLConicalGradientValues }
+
+function BLConicalGradientValues(const AX0, AY0, AAngle: Double): TBLConicalGradientValues; inline;
+begin
+  Result.Reset(AX0, AY0, AAngle);
+end;
+
+procedure TBLConicalGradientValues.Reset(const AX0, AY0, AAngle: Double);
+begin
+  FHandle.x0 := AX0;
+  FHandle.y0 := AY0;
+  FHandle.angle := AAngle;
+end;
+
+procedure TBLConicalGradientValues.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+{ TBLGradient }
+
+procedure TBLGradient.AddStop(const AOffset: Double; const ARgba: TBLRgba64);
+begin
+  _BLCheck(blGradientAddStopRgba64(@FHandle, AOffset, ARgba.FHandle.value));
+end;
+
+procedure TBLGradient.AddStop(const AOffset: Double; const ARgba: TBLRgba32);
+begin
+  _BLCheck(blGradientAddStopRgba32(@FHandle, AOffset, ARgba.FHandle.value));
+end;
+
+constructor TBLGradient.Create;
+begin
+  inherited;
+  blGradientInit(@FHandle);
+end;
+
+constructor TBLGradient.Create(const AValues: TBLRadialGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>);
+begin
+  inherited Create;
+  _BLCheck(blGradientInitAs(@FHandle, BL_GRADIENT_TYPE_RADIAL, @AValues.FHandle,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), nil));
+end;
+
+constructor TBLGradient.Create(const AValues: TBLLinearGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>);
+begin
+  inherited Create;
+  _BLCheck(blGradientInitAs(@FHandle, BL_GRADIENT_TYPE_LINEAR, @AValues.FHandle,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), nil));
+end;
+
+constructor TBLGradient.Create(const AType: TBLGradientType;
+  const AValues: PDouble);
+begin
+  inherited Create;
+  _BLCheck(blGradientInitAs(@FHandle, Ord(AType), AValues, BL_EXTEND_MODE_PAD,
+    nil, 0, nil));
+end;
+
+constructor TBLGradient.Create(const AValues: TBLConicalGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>);
+begin
+  inherited Create;
+  _BLCheck(blGradientInitAs(@FHandle, BL_GRADIENT_TYPE_CONICAL, @AValues.FHandle,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), nil));
+end;
+
+constructor TBLGradient.Create(const AValues: TBLConicalGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+  const AMatrix: TBLMatrix2D);
+begin
+  inherited Create;
+  _BLCheck(blGradientInitAs(@FHandle, BL_GRADIENT_TYPE_CONICAL, @AValues.FHandle,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), @AMatrix));
+end;
+
+constructor TBLGradient.Create(const AHandle: BLGradientCore;
+  const AIsReference: Boolean);
+begin
+  inherited Create;
+  FHandle := AHandle;
+  FIsReference := AIsReference;
+end;
+
+constructor TBLGradient.Create(const AValues: TBLRadialGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+  const AMatrix: TBLMatrix2D);
+begin
+  inherited Create;
+  _BLCheck(blGradientInitAs(@FHandle, BL_GRADIENT_TYPE_RADIAL, @AValues.FHandle,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), @AMatrix));
+end;
+
+constructor TBLGradient.Create(const AValues: TBLLinearGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+  const AMatrix: TBLMatrix2D);
+begin
+  inherited Create;
+  _BLCheck(blGradientInitAs(@FHandle, BL_GRADIENT_TYPE_LINEAR, @AValues.FHandle,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), @AMatrix));
+end;
+
+destructor TBLGradient.Destroy;
+begin
+  if (not FIsReference) then
+    blGradientDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLGradient.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLGradient) then
+    Result := blGradientEquals(@FHandle, @TBLGradient(Obj).FHandle)
+  else
+    Result := False;
+end;
+
+function TBLGradient.Equals(const AOther: IBLGradient): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := blGradientEquals(@FHandle, AOther.Handle);
+end;
+
+function TBLGradient.GetAllStops: PBLGradientStop;
+begin
+  Result := PBLGradientStop(FHandle.impl.stops.stops);
+end;
+
+function TBLGradient.GetAngle: Double;
+begin
+  Result := FHandle.impl.values[BL_GRADIENT_VALUE_CONICAL_ANGLE];
+end;
+
+function TBLGradient.GetCapacity: Integer;
+begin
+  Result := FHandle.impl.capacity;
+end;
+
+function TBLGradient.GetConical: TBLConicalGradientValues;
+begin
+  Result.FHandle := FHandle.impl.conical;
+end;
+
+function TBLGradient.GetExtendMode: TBLExtendMode;
+begin
+  Result := TBLExtendMode(FHandle.impl.extendMode);
+end;
+
+function TBLGradient.GetGradientType: TBLGradientType;
+begin
+  Result := TBLGradientType(FHandle.impl.gradientType);
+end;
+
+function TBLGradient.GetHandle: PBLGradientCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLGradient.GetHasMatrix: Boolean;
+begin
+  Result := ((FHandle.impl.matrixType and BL_MATRIX2D_TYPE_IDENTITY) <> 0);
+end;
+
+function TBLGradient.GetIsEmpty: Boolean;
+begin
+  Result := (FHandle.impl.stops.size = 0);
+end;
+
+function TBLGradient.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLGradient.GetLinear: TBLLinearGradientValues;
+begin
+  Result.FHandle := FHandle.impl.linear;
+end;
+
+function TBLGradient.GetMatrix: TBLMatrix2D;
+begin
+  Result.FHandle := FHandle.impl.matrix;
+end;
+
+function TBLGradient.GetMatrixType: TBLMatrix2DType;
+begin
+  Result := TBLMatrix2DType(FHandle.impl.matrixType);
+end;
+
+function TBLGradient.GetR0: Double;
+begin
+  Result := FHandle.impl.values[BL_GRADIENT_VALUE_RADIAL_R0];
+end;
+
+function TBLGradient.GetRadial: TBLRadialGradientValues;
+begin
+  Result.FHandle := FHandle.impl.radial;
+end;
+
+function TBLGradient.GetSize: Integer;
+begin
+  Result := FHandle.impl.stops.size;
+end;
+
+function TBLGradient.GetStop(const AIndex: Integer): TBLGradientStop;
+begin
+  Assert(Cardinal(AIndex) < FHandle.impl.stops.size);
+  Result := TBLGradientStop(FHandle.impl.stops.stops[AIndex]);
+end;
+
+function TBLGradient.GetValue(const AIndex: TBLGradientValue): Double;
+begin
+  Result := FHandle.impl.values[Ord(AIndex)];
+end;
+
+function TBLGradient.GetX0: Double;
+begin
+  Result := FHandle.impl.values[BL_GRADIENT_VALUE_COMMON_X0];
+end;
+
+function TBLGradient.GetX1: Double;
+begin
+  Result := FHandle.impl.values[BL_GRADIENT_VALUE_COMMON_X1];
+end;
+
+function TBLGradient.GetY0: Double;
+begin
+  Result := FHandle.impl.values[BL_GRADIENT_VALUE_COMMON_Y0];
+end;
+
+function TBLGradient.GetY1: Double;
+begin
+  Result := FHandle.impl.values[BL_GRADIENT_VALUE_COMMON_Y1];
+end;
+
+function TBLGradient.IndexOfStop(const AOffset: Double): Integer;
+begin
+  Result := blGradientIndexOfStop(@FHandle, AOffset);
+end;
+
+procedure TBLGradient.Initialize(const AValues: TBLConicalGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+  const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blGradientCreate(@FHandle, BL_GRADIENT_TYPE_CONICAL, @AValues,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), @AMatrix));
+end;
+
+procedure TBLGradient.Initialize(const AValues: TBLConicalGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>);
+begin
+  _BLCheck(blGradientCreate(@FHandle, BL_GRADIENT_TYPE_CONICAL, @AValues,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), nil));
+end;
+
+procedure TBLGradient.Initialize(const AValues: TBLRadialGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>);
+begin
+  _BLCheck(blGradientCreate(@FHandle, BL_GRADIENT_TYPE_RADIAL, @AValues,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), nil));
+end;
+
+procedure TBLGradient.Initialize(const AValues: TBLLinearGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>);
+begin
+  _BLCheck(blGradientCreate(@FHandle, BL_GRADIENT_TYPE_LINEAR, @AValues,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), nil));
+end;
+
+procedure TBLGradient.Initialize(const AValues: TBLRadialGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+  const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blGradientCreate(@FHandle, BL_GRADIENT_TYPE_RADIAL, @AValues,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), @AMatrix));
+end;
+
+procedure TBLGradient.Initialize(const AValues: TBLLinearGradientValues;
+  const AExtendMode: TBLExtendMode; const AStops: TArray<TBLGradientStop>;
+  const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blGradientCreate(@FHandle, BL_GRADIENT_TYPE_LINEAR, @AValues,
+    Ord(AExtendMode), Pointer(AStops), Length(AStops), @AMatrix));
+end;
+
+procedure TBLGradient.PostRotate(const AAngle: Double);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE, @AAngle));
+end;
+
+procedure TBLGradient.PostRotate(const AAngle, AX, AY: Double);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AX;
+  Data[2] := AY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLGradient.PostRotate(const AAngle: Double; const AP: TBLPointI);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLGradient.PostRotate(const AAngle: Double; const AP: TBLPoint);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLGradient.PostScale(const AP: TBLPoint);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @AP));
+end;
+
+procedure TBLGradient.PostScale(const AP: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AP.FHandle.x;
+  Data[1] := AP.FHandle.y;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @Data));
+end;
+
+procedure TBLGradient.PostScale(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @Data));
+end;
+
+procedure TBLGradient.PostScale(const AXY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AXY;
+  Data[1] := AXY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @Data));
+end;
+
+procedure TBLGradient.PostSkew(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SKEW, @Data));
+end;
+
+procedure TBLGradient.PostSkew(const AP: TBLPoint);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SKEW, @AP));
+end;
+
+procedure TBLGradient.PostTransform(const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSFORM, @AMatrix));
+end;
+
+procedure TBLGradient.PostTranslate(const AP: TBLPoint);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSLATE, @AP));
+end;
+
+procedure TBLGradient.PostTranslate(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSLATE, @Data));
+end;
+
+procedure TBLGradient.PostTranslate(const AP: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AP.FHandle.x;
+  Data[1] := AP.FHandle.y;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSLATE, @Data));
+end;
+
+procedure TBLGradient.RemoveStop(const AIndex: Integer);
+begin
+  _BLCheck(blGradientRemoveStop(@FHandle, AIndex));
+end;
+
+procedure TBLGradient.RemoveStopByOffset(const AOffset: Double;
+  const AAll: Boolean);
+begin
+  _BLCheck(blGradientRemoveStopByOffset(@FHandle, AOffset, Ord(AAll)));
+end;
+
+procedure TBLGradient.RemoveStops(const ARange: TBLRange);
+begin
+  _BLCheck(blGradientRemoveStops(@FHandle, ARange.FHandle.start, ARange.FHandle.&end));
+end;
+
+procedure TBLGradient.RemoveStopsByOffset(const AOffsetMin, AOffsetMax: Double);
+begin
+  _BLCheck(blGradientRemoveStopsFromTo(@FHandle, AOffsetMin, AOffsetMax));
+end;
+
+procedure TBLGradient.ReplaceStop(const AIndex: Integer; const AOffset: Double;
+  const ARgba: TBLRgba64);
+begin
+  _BLCheck(blGradientReplaceStopRgba64(@FHandle, AIndex, AOffset, ARgba.FHandle.value));
+end;
+
+procedure TBLGradient.ReplaceStop(const AIndex: Integer; const AOffset: Double;
+  const ARgba: TBLRgba32);
+begin
+  _BLCheck(blGradientReplaceStopRgba32(@FHandle, AIndex, AOffset, ARgba.FHandle.value));
+end;
+
+procedure TBLGradient.Reserve(const ACount: Integer);
+begin
+  _BLCheck(blGradientReserve(@FHandle, ACount));
+end;
+
+procedure TBLGradient.Reset;
+begin
+  _BLCheck(blGradientReset(@FHandle));
+end;
+
+procedure TBLGradient.ResetExtendMode;
+begin
+  _BLCheck(blGradientSetExtendMode(@FHandle, BL_EXTEND_MODE_PAD));
+end;
+
+procedure TBLGradient.ResetMatrix;
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_RESET, nil));
+end;
+
+procedure TBLGradient.ResetStops;
+begin
+  _BLCheck(blGradientResetStops(@FHandle));
+end;
+
+procedure TBLGradient.Rotate(const AAngle: Double; const AP: TBLPoint);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLGradient.Rotate(const AAngle, AX, AY: Double);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AX;
+  Data[2] := AY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLGradient.Rotate(const AAngle: Double);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE, @AAngle));
+end;
+
+procedure TBLGradient.Rotate(const AAngle: Double; const AP: TBLPointI);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLGradient.Scale(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @Data));
+end;
+
+procedure TBLGradient.Scale(const AXY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AXY;
+  Data[1] := AXY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @Data));
+end;
+
+procedure TBLGradient.Scale(const AP: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AP.FHandle.x;
+  Data[1] := AP.FHandle.y;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @Data));
+end;
+
+procedure TBLGradient.Scale(const AP: TBLPoint);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @AP));
+end;
+
+procedure TBLGradient.SetAngle(const AValue: Double);
+begin
+  _BLCheck(blGradientSetValue(@FHandle, BL_GRADIENT_VALUE_CONICAL_ANGLE, AValue));
+end;
+
+procedure TBLGradient.SetConical(const AValue: TBLConicalGradientValues);
+begin
+  _BLCheck(blGradientSetValues(@FHandle, 0, @AValue, SizeOf(AValue) div SizeOf(Double)));
+end;
+
+procedure TBLGradient.SetExtendMode(const AValue: TBLExtendMode);
+begin
+  _BLCheck(blGradientSetExtendMode(@FHandle, Ord(AValue)));
+end;
+
+procedure TBLGradient.SetGradientType(const AValue: TBLGradientType);
+begin
+  _BLCheck(blGradientSetType(@FHandle, Ord(AValue)));
+end;
+
+procedure TBLGradient.SetLinear(const AValue: TBLLinearGradientValues);
+begin
+  _BLCheck(blGradientSetValues(@FHandle, 0, @AValue, SizeOf(AValue) div SizeOf(Double)));
+end;
+
+procedure TBLGradient.SetMatrix(const AValue: TBLMatrix2D);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ASSIGN, @AValue));
+end;
+
+procedure TBLGradient.SetR0(const AValue: Double);
+begin
+  _BLCheck(blGradientSetValue(@FHandle, BL_GRADIENT_VALUE_RADIAL_R0, AValue));
+end;
+
+procedure TBLGradient.SetRadial(const AValue: TBLRadialGradientValues);
+begin
+  _BLCheck(blGradientSetValues(@FHandle, 0, @AValue, SizeOf(AValue) div SizeOf(Double)));
+end;
+
+procedure TBLGradient.SetStop(const AIndex: Integer;
+  const AValue: TBLGradientStop);
+begin
+  _BLCheck(blGradientReplaceStopRgba64(@FHandle, AIndex, AValue.FHandle.offset,
+    AValue.FHandle.rgba.value));
+end;
+
+procedure TBLGradient.SetStops(const AStops: TArray<TBLGradientStop>);
+begin
+  _BLCheck(blGradientAssignStops(@FHandle, Pointer(AStops), Length(AStops)));
+end;
+
+procedure TBLGradient.SetValue(const AIndex: TBLGradientValue;
+  const AValue: Double);
+begin
+  _BLCheck(blGradientSetValue(@FHandle, Ord(AIndex), AValue));
+end;
+
+procedure TBLGradient.SetValues(const AValues: TBLLinearGradientValues);
+begin
+  _BLCheck(blGradientSetValues(@FHandle, 0, @AValues, SizeOf(TBLLinearGradientValues) div SizeOf(Double)));
+end;
+
+procedure TBLGradient.SetValues(const AValues: TBLRadialGradientValues);
+begin
+  _BLCheck(blGradientSetValues(@FHandle, 0, @AValues, SizeOf(TBLRadialGradientValues) div SizeOf(Double)));
+end;
+
+procedure TBLGradient.SetValues(const AValues: TBLConicalGradientValues);
+begin
+  _BLCheck(blGradientSetValues(@FHandle, 0, @AValues, SizeOf(TBLConicalGradientValues) div SizeOf(Double)));
+end;
+
+procedure TBLGradient.SetValues(const AIndex: TBLGradientValue;
+  const AValues: TArray<Double>);
+begin
+  _BLCheck(blGradientSetValues(@FHandle, Ord(AIndex), Pointer(AValues), Length(AValues)));
+end;
+
+procedure TBLGradient.SetX0(const AValue: Double);
+begin
+  _BLCheck(blGradientSetValue(@FHandle, BL_GRADIENT_VALUE_COMMON_X0, AValue));
+end;
+
+procedure TBLGradient.SetX1(const AValue: Double);
+begin
+  _BLCheck(blGradientSetValue(@FHandle, BL_GRADIENT_VALUE_COMMON_X1, AValue));
+end;
+
+procedure TBLGradient.SetY0(const AValue: Double);
+begin
+  _BLCheck(blGradientSetValue(@FHandle, BL_GRADIENT_VALUE_COMMON_Y0, AValue));
+end;
+
+procedure TBLGradient.SetY1(const AValue: Double);
+begin
+  _BLCheck(blGradientSetValue(@FHandle, BL_GRADIENT_VALUE_COMMON_Y1, AValue));
+end;
+
+procedure TBLGradient.Shrink;
+begin
+  _BLCheck(blGradientShrink(@FHandle));
+end;
+
+procedure TBLGradient.Skew(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SKEW, @Data));
+end;
+
+procedure TBLGradient.Skew(const AP: TBLPoint);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SKEW, @AP));
+end;
+
+procedure TBLGradient.Transform(const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSFORM, @AMatrix));
+end;
+
+procedure TBLGradient.Translate(const AP: TBLPoint);
+begin
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSLATE, @AP));
+end;
+
+procedure TBLGradient.Translate(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSLATE, @Data));
+end;
+
+procedure TBLGradient.Translate(const AP: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AP.FHandle.x;
+  Data[1] := AP.FHandle.y;
+  _BLCheck(blGradientApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSLATE, @Data));
+end;
+
+{$ENDREGION 'Gradient'}
+
+{$REGION 'Region'}
+
+{ TBLRegion }
+
+procedure TBLRegion.Assign(const ABoxes: PBLBoxI; const ACount: Integer);
+begin
+  _BLCheck(blRegionAssignBoxIArray(@FHandle, Pointer(ABoxes), ACount));
+end;
+
+procedure TBLRegion.Assign(const ABoxes: TArray<TBLBoxI>);
+begin
+  _BLCheck(blRegionAssignBoxIArray(@FHandle, Pointer(ABoxes), Length(ABoxes)));
+end;
+
+procedure TBLRegion.Assign(const ABox: TBLBoxI);
+begin
+  _BLCheck(blRegionAssignBoxI(@FHandle, @ABox));
+end;
+
+procedure TBLRegion.Assign(const ARects: PBLRectI; const ACount: Integer);
+begin
+  _BLCheck(blRegionAssignRectIArray(@FHandle, Pointer(ARects), ACount));
+end;
+
+procedure TBLRegion.Assign(const ARect: TBLRectI);
+begin
+  _BLCheck(blRegionAssignRectI(@FHandle, @ARect));
+end;
+
+procedure TBLRegion.Assign(const ARects: TArray<TBLRectI>);
+begin
+  _BLCheck(blRegionAssignRectIArray(@FHandle, Pointer(ARects), Length(ARects)));
+end;
+
+procedure TBLRegion.Clear;
+begin
+  _BLCheck(blRegionClear(@FHandle));
+end;
+
+function TBLRegion.Clone: IBLRegion;
+begin
+  Result := TBLRegion.Create;
+  _BLCheck(blRegionAssignDeep(Result.Handle, @FHandle));
+end;
+
+class function TBLRegion.Combine(const AA, AB: IBLRegion;
+  const ABooleanOp: TBLBooleanOp): IBLRegion;
+begin
+  Result := TBLRegion.Create;
+  if (AA <> nil) and (AB <> nil) then
+    _BLCheck(blRegionCombine(Result.Handle, AA.Handle, AB.Handle, Ord(ABooleanOp)));
+end;
+
+procedure TBLRegion.Combine(const ABox: TBLBoxI;
+  const ABooleanOp: TBLBooleanOp);
+begin
+  _BLCheck(blRegionCombineRB(@FHandle, @FHandle, @ABox, Ord(ABooleanOp)));
+end;
+
+procedure TBLRegion.Combine(const ARegion: IBLRegion;
+  const ABooleanOp: TBLBooleanOp);
+begin
+  if (ARegion <> nil) then
+    _BLCheck(blRegionCombine(@FHandle, @FHandle, ARegion.Handle, Ord(ABooleanOp)));
+end;
+
+class function TBLRegion.Combine(const AA, AB: TBLBoxI;
+  const ABooleanOp: TBLBooleanOp): IBLRegion;
+begin
+  Result := TBLRegion.Create;
+  _BLCheck(blRegionCombineBB(Result.Handle, @AA, @AB, Ord(ABooleanOp)));
+end;
+
+class function TBLRegion.Combine(const AA: TBLBoxI; const AB: IBLRegion;
+  const ABooleanOp: TBLBooleanOp): IBLRegion;
+begin
+  Result := TBLRegion.Create;
+  if (AB <> nil) then
+    _BLCheck(blRegionCombineBR(Result.Handle, @AA, AB.Handle, Ord(ABooleanOp)));
+end;
+
+class function TBLRegion.Combine(const AA: IBLRegion; const AB: TBLBoxI;
+  const ABooleanOp: TBLBooleanOp): IBLRegion;
+begin
+  Result := TBLRegion.Create;
+  if (AA <> nil) then
+    _BLCheck(blRegionCombineRB(Result.Handle, AA.Handle, @AB, Ord(ABooleanOp)));
+end;
+
+constructor TBLRegion.Create;
+begin
+  inherited;
+  blRegionInit(@FHandle);
+end;
+
+destructor TBLRegion.Destroy;
+begin
+  blRegionDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLRegion.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLRegion) then
+    Result := blRegionEquals(@FHandle, @TBLRegion(Obj).FHandle)
+  else
+    Result := False;
+end;
+
+function TBLRegion.Equals(const AOther: IBLRegion): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := blRegionEquals(@FHandle, AOther.Handle);
+end;
+
+function TBLRegion.GetBoundingBox: TBLBoxI;
+begin
+  Result.FHandle := FHandle.impl.boundingBox;
+end;
+
+function TBLRegion.GetCapacity: Integer;
+begin
+  Result := FHandle.impl.capacity;
+end;
+
+function TBLRegion.GetData: PBLBoxI;
+begin
+  Result := Pointer(FHandle.impl.data.data);
+end;
+
+function TBLRegion.GetDataEnd: PBLBoxI;
+begin
+  Result := Pointer(FHandle.impl.data.data);
+  Inc(Result, FHandle.impl.data.size);
+end;
+
+function TBLRegion.GetHandle: PBLRegionCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLRegion.GetIsComplex: Boolean;
+begin
+  Result := (FHandle.impl.data.size > 1);
+end;
+
+function TBLRegion.GetIsEmpty: Boolean;
+begin
+  Result := (FHandle.impl.data.size = 0);
+end;
+
+function TBLRegion.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLRegion.GetIsRect: Boolean;
+begin
+  Result := (FHandle.impl.data.size = 1);
+end;
+
+function TBLRegion.GetRegionType: TBLRegionType;
+begin
+  Result := TBLRegionType(Min(FHandle.impl.data.size, BL_REGION_TYPE_COMPLEX));
+end;
+
+function TBLRegion.GetSize: Integer;
+begin
+  Result := FHandle.impl.data.size;
+end;
+
+function TBLRegion.GetView: TBLRegionView;
+begin
+  Result.FHandle := BLArrayView(FHandle.impl.data.view);
+end;
+
+function TBLRegion.HitTest(const ABox: TBLBoxI): TBLHitTest;
+begin
+  Result := TBLHitTest(blRegionHitTestBoxI(@FHandle, @ABox));
+end;
+
+function TBLRegion.HitTest(const APt: TBLPointI): TBLHitTest;
+begin
+  Result := TBLHitTest(blRegionHitTest(@FHandle, @APt));
+end;
+
+class function TBLRegion.IntersectAndClip(const AA, AB: IBLRegion;
+  const AClipBox: TBLBoxI): IBLRegion;
+begin
+  Result := TBLRegion.Create;
+  if Assigned(AA) and Assigned(AB) then
+    _BLCheck(blRegionIntersectAndClip(Result.Handle, AA.Handle, AB.Handle, @AClipBox));
+end;
+
+procedure TBLRegion.IntersectAndClip(const AR: IBLRegion;
+  const AClipBox: TBLBoxI);
+begin
+  if Assigned(AR) then
+    _BLCheck(blRegionIntersectAndClip(@FHandle, @FHandle, AR.Handle, @AClipBox));
+end;
+
+procedure TBLRegion.Reserve(const ACount: Integer);
+begin
+  _BLCheck(blRegionReserve(@FHandle, ACount));
+end;
+
+procedure TBLRegion.Reset;
+begin
+  _BLCheck(blRegionReset(@FHandle));
+end;
+
+procedure TBLRegion.Shrink;
+begin
+  _BLCheck(blRegionShrink(@FHandle));
+end;
+
+procedure TBLRegion.Translate(const APt: TBLPointI);
+begin
+  _BLCheck(blRegionTranslate(@FHandle, @FHandle, @APt));
+end;
+
+class function TBLRegion.Translate(const AR: IBLRegion;
+  const APt: TBLPointI): IBLRegion;
+begin
+  Result := TBLRegion.Create;
+  if Assigned(AR) then
+    _BLCheck(blRegionTranslate(Result.Handle, AR.Handle, @APt));
+end;
+
+class function TBLRegion.TranslateAndClip(const AR: IBLRegion;
+  const APt: TBLPointI; const AClipBox: TBLBoxI): IBLRegion;
+begin
+  Result := TBLRegion.Create;
+  if Assigned(AR) then
+    _BLCheck(blRegionTranslateAndClip(Result.Handle, AR.Handle, @APt, @AClipBox));
+end;
+
+procedure TBLRegion.TranslateAndClip(const APt: TBLPointI;
+  const AClipBox: TBLBoxI);
+begin
+  _BLCheck(blRegionTranslateAndClip(@FHandle, @FHandle, @APt, @AClipBox));
+end;
+
+{$ENDREGION 'Region'}
+
+{$REGION 'Path'}
+
+{ TBLApproximationOptions }
+
+class constructor TBLApproximationOptions.Create;
+begin
+  FillChar(FDefault, SizeOf(FDefault), 0);
+  FDefault.flattenTolerance := 0.2;
+  FDefault.simplifyTolerance := 0.05;
+  FDefault.offsetParameter := 0.414213562;
+end;
+
+class function TBLApproximationOptions.GetDefault: TBLApproximationOptions;
+begin
+  Result.FHandle := FDefault;
+end;
+
+function TBLApproximationOptions.GetFlattenMode: TBLFlattenMode;
+begin
+  Result := TBLFlattenMode(FHandle.flattenMode);
+end;
+
+function TBLApproximationOptions.GetOffsetMode: TBLOffsetMode;
+begin
+  Result := TBLOffsetMode(FHandle.offsetMode);
+end;
+
+procedure TBLApproximationOptions.SetFlattenMode(const AValue: TBLFlattenMode);
+begin
+  FHandle.flattenMode := Ord(AValue);
+end;
+
+procedure TBLApproximationOptions.SetOffsetMode(const AValue: TBLOffsetMode);
+begin
+  FHandle.offsetMode := Ord(AValue);
+end;
+
+{ TBLStrokeOptions }
+
+function TBLStrokeOptions.GetDashArray: TArray<Double>;
+begin
+  Result := TBLUtils.BLArrayToArray<Double>(FHandle.dashArray);
+end;
+
+function TBLStrokeOptions.GetEndCap: TBLStrokeCap;
+begin
+  Result := TBLStrokeCap(FHandle.options.endCap);
+end;
+
+function TBLStrokeOptions.GetJoin: TBLStrokeJoin;
+begin
+  Result := TBLStrokeJoin(FHandle.options.join);
+end;
+
+function TBLStrokeOptions.GetStartCap: TBLStrokeCap;
+begin
+  Result := TBLStrokeCap(FHandle.options.startCap);
+end;
+
+function TBLStrokeOptions.GetTransformOrder: TBLStrokeTransformOrder;
+begin
+  Result := TBLStrokeTransformOrder(FHandle.options.transformOrder);
+end;
+
+procedure TBLStrokeOptions.Reset;
+begin
+  if (FScope <> nil) then
+    blStrokeOptionsReset(@FHandle)
+  else
+  begin
+    blStrokeOptionsInit(@FHandle);
+    FScope := TScope.Create(@FHandle);
+  end;
+end;
+
+procedure TBLStrokeOptions.SetCaps(const AStartCap, AEndCap: TBLStrokeCap);
+begin
+  FHandle.options.startCap := Ord(AStartCap);
+  FHandle.options.endCap := Ord(AEndCap);
+end;
+
+procedure TBLStrokeOptions.SetCaps(const ACap: TBLStrokeCap);
+begin
+  FHandle.options.startCap := Ord(ACap);
+  FHandle.options.endCap := Ord(ACap);
+end;
+
+procedure TBLStrokeOptions.SetDashArray(const AValue: TArray<Double>);
+var
+  Value: IBLArray;
+begin
+  blArrayReset(@FHandle.dashArray);
+  Value := TBLUtils.ArrayToBLArray<Double>(AValue);
+  Value.RevokeOwnership;
+  FHandle.dashArray := Value.Handle^;
+end;
+
+procedure TBLStrokeOptions.SetEndCap(const AValue: TBLStrokeCap);
+begin
+  FHandle.options.endCap := Ord(AValue);
+end;
+
+procedure TBLStrokeOptions.SetJoin(const AValue: TBLStrokeJoin);
+begin
+  FHandle.options.join := Ord(AValue);
+end;
+
+procedure TBLStrokeOptions.SetStartCap(const AValue: TBLStrokeCap);
+begin
+  FHandle.options.startCap := Ord(AValue);
+end;
+
+procedure TBLStrokeOptions.SetTransformOrder(
+  const AValue: TBLStrokeTransformOrder);
+begin
+  FHandle.options.transformOrder := Ord(AValue);
+end;
+
+{ TBLStrokeOptions.TScope }
+
+constructor TBLStrokeOptions.TScope.Create(const AHandle: PBLStrokeOptionsCore);
+begin
+  inherited Create;
+  FHandle := AHandle;
+end;
+
+destructor TBLStrokeOptions.TScope.Destroy;
+begin
+  blStrokeOptionsDestroy(FHandle);
+  inherited;
+end;
+
+{ TBLPathView }
+
+function BLPathView(const ACommands: PBLPathCmd; const AVertices: PBLPoint;
+  const ACount: Integer): TBLPathView; inline;
+begin
+  Result.Reset(ACommands, AVertices, ACount);
+end;
+
+function TBLPathView.GetCommands: PBLPathCmd;
+begin
+  Result := Pointer(FHandle.commandData);
+end;
+
+function TBLPathView.GetCount: Integer;
+begin
+  Result := FHandle.size;
+end;
+
+function TBLPathView.GetVertices: PBLPoint;
+begin
+  Result := Pointer(FHandle.vertexData);
+end;
+
+procedure TBLPathView.Reset(const ACommands: PBLPathCmd;
+  const AVertices: PBLPoint; const ACount: Integer);
+begin
+  FHandle.commandData := Pointer(ACommands);
+  FHandle.vertexData := Pointer(AVertices);
+  FHandle.size := ACount;
+end;
+
+procedure TBLPathView.Reset;
+begin
+  FHandle.commandData := nil;
+  FHandle.vertexData := nil;
+  FHandle.size := 0;
+end;
+
+{ TBLPath }
+
+procedure TBLPath.AddArc(const AArc: TBLArc;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARC, @AArc, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddArc(const AArc: TBLArc; const AMatrix: TBLMatrix2D;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARC, @AArc, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBox(const ABox: TBLBoxI;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddBoxI(@FHandle, @ABox, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBox(const ABox: TBLBox;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddBoxD(@FHandle, @ABox, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBox(const AX0, AY0, AX1, AY1: Double;
+  const ADirection: TBLGeometryDirection);
+var
+  Box: TBLBox;
+begin
+  Box.Reset(AX0, AY0, AX1, AY1);
+  _BLCheck(blPathAddBoxD(@FHandle, @Box, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBoxArray(const ABoxes: TBLArrayView<TBLBoxI>;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @ABoxes.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBoxArray(const ABoxes: PBLBoxI; const ACount: Integer;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLBoxI>;
+begin
+  View.Reset(ABoxes, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @View.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBoxArray(const ABoxes: TBLArrayView<TBLBoxI>;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @ABoxes.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBoxArray(const ABoxes: PBLBoxI; const ACount: Integer;
+  const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLBoxI>;
+begin
+  View.Reset(ABoxes, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @View.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBoxArray(const ABoxes: PBLBox; const ACount: Integer;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLBox>;
+begin
+  View.Reset(ABoxes, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @View.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBoxArray(const ABoxes: PBLBox; const ACount: Integer;
+  const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLBox>;
+begin
+  View.Reset(ABoxes, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @View.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBoxArray(const ABoxes: TBLArrayView<TBLBox>;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @ABoxes.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddBoxArray(const ABoxes: TBLArrayView<TBLBox>;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @ABoxes.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddChord(const AChord: TBLArc;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_CHORD, @AChord, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddChord(const AChord: TBLArc; const AMatrix: TBLMatrix2D;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_CHORD, @AChord, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddCircle(const ACircle: TBLCircle;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_CIRCLE, @ACircle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddCircle(const ACircle: TBLCircle;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_CIRCLE, @ACircle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddEllipse(const AEllipse: TBLEllipse;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ELLIPSE, @AEllipse, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddEllipse(const AEllipse: TBLEllipse;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ELLIPSE, @AEllipse, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddGeometry(const AGeometryType: TBLGeometryType;
+  const AGeometryData: Pointer; const AMatrix: PBLMatrix2D;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, Ord(AGeometryType), AGeometryData,
+    @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddLine(const ALine: TBLLine; const AMatrix: TBLMatrix2D;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_LINE, @ALine, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddLine(const ALine: TBLLine;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_LINE, @ALine, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPath(const APath: IBLPath; const ARange: TBLRange);
+begin
+  if (APath <> nil) then
+    _BLCheck(blPathAddPath(@FHandle, APath.Handle, @ARange));
+end;
+
+procedure TBLPath.AddPath(const APath: IBLPath);
+begin
+  if (APath <> nil) then
+    _BLCheck(blPathAddPath(@FHandle, APath.Handle, nil));
+end;
+
+procedure TBLPath.AddPath(const APath: IBLPath; const ATranslate: TBLPoint);
+begin
+  if (APath <> nil) then
+    _BLCheck(blPathAddTranslatedPath(@FHandle, APath.Handle, nil, @ATranslate));
+end;
+
+procedure TBLPath.AddPath(const APath: IBLPath; const ARange: TBLRange;
+  const AMatrix: TBLMatrix2D);
+begin
+  if (APath <> nil) then
+    _BLCheck(blPathAddTransformedPath(@FHandle, APath.Handle, @ARange, @AMatrix));
+end;
+
+procedure TBLPath.AddPath(const APath: IBLPath; const AMatrix: TBLMatrix2D);
+begin
+  if (APath <> nil) then
+    _BLCheck(blPathAddTransformedPath(@FHandle, APath.Handle, nil, @AMatrix));
+end;
+
+procedure TBLPath.AddPath(const APath: IBLPath; const ARange: TBLRange;
+  const ATranslate: TBLPoint);
+begin
+  if (APath <> nil) then
+    _BLCheck(blPathAddTranslatedPath(@FHandle, APath.Handle, @ARange, @ATranslate));
+end;
+
+procedure TBLPath.AddPie(const APie: TBLArc; const AMatrix: TBLMatrix2D;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_PIE, @APie, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPie(const APie: TBLArc;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_PIE, @APie, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolygon(const APolygon: TBLArrayView<TBLPoint>;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @APolygon.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolygon(const APolygon: TBLArrayView<TBLPoint>;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @APolygon.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolygon(const APolygon: PBLPoint; const ACount: Integer;
+  const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(APolygon, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @View.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolygon(const APolygon: PBLPoint; const ACount: Integer;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(APolygon, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @View.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolygon(const APolygon: TBLArrayView<TBLPointI>;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @APolygon.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolygon(const APolygon: TBLArrayView<TBLPointI>;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @APolygon.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolygon(const APolygon: PBLPointI; const ACount: Integer;
+  const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(APolygon, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @View.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolygon(const APolygon: PBLPointI; const ACount: Integer;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(APolygon, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @View.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolyline(const APolyline: TBLArrayView<TBLPoint>;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINED, @APolyline.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolyline(const APolyline: TBLArrayView<TBLPoint>;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINED, @APolyline.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolyline(const APolyline: PBLPoint; const ACount: Integer;
+  const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(APolyline, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINED, @View.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolyline(const APolyline: PBLPoint; const ACount: Integer;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(APolyline, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINED, @View.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolyline(const APolyline: TBLArrayView<TBLPointI>;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINEI, @APolyline.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolyline(const APolyline: TBLArrayView<TBLPointI>;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINEI, @APolyline.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolyline(const APolyline: PBLPointI; const ACount: Integer;
+  const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(APolyline, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINEI, @View.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddPolyline(const APolyline: PBLPointI; const ACount: Integer;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(APolyline, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINEI, @View.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRect(const AX, AY, AW, AH: Double;
+  const ADirection: TBLGeometryDirection);
+var
+  Rect: TBLRect;
+begin
+  Rect.Reset(AX, AY, AW, AH);
+  _BLCheck(blPathAddRectD(@FHandle, @Rect, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRect(const ARect: TBLRect;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddRectD(@FHandle, @ARect, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRect(const ARect: TBLRectI;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddRectI(@FHandle, @ARect, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRectArray(const ARects: PBLRectI; const ACount: Integer;
+  const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLRectI>;
+begin
+  View.Reset(ARects, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @View.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRectArray(const ARects: TBLArrayView<TBLRectI>;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @ARects.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRectArray(const ARects: TBLArrayView<TBLRectI>;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @ARects.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRectArray(const ARects: PBLRectI; const ACount: Integer;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLRectI>;
+begin
+  View.Reset(ARects, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @View.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRectArray(const ARects: PBLRect; const ACount: Integer;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLRect>;
+begin
+  View.Reset(ARects, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @View.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRectArray(const ARects: PBLRect; const ACount: Integer;
+  const ADirection: TBLGeometryDirection);
+var
+  View: TBLArrayView<TBLRect>;
+begin
+  View.Reset(ARects, ACount);
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @View.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRectArray(const ARects: TBLArrayView<TBLRect>;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @ARects.FHandle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRectArray(const ARects: TBLArrayView<TBLRect>;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @ARects.FHandle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRegion(const ARegion: IBLRegion;
+  const ADirection: TBLGeometryDirection);
+begin
+  if (ARegion <> nil) then
+    _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_REGION, ARegion.Handle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRegion(const ARegion: IBLRegion;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  if (ARegion <> nil) then
+    _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_REGION, ARegion.Handle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddReversedPath(const APath: IBLPath;
+  const AReverseMode: TBLPathReverseMode);
+begin
+  if (APath <> nil) then
+    _BLCheck(blPathAddReversedPath(@FHandle, APath.Handle, nil, Ord(AReverseMode)));
+end;
+
+procedure TBLPath.AddReversedPath(const APath: IBLPath; const ARange: TBLRange;
+  const AReverseMode: TBLPathReverseMode);
+begin
+  if (APath <> nil) then
+    _BLCheck(blPathAddReversedPath(@FHandle, APath.Handle, @ARange, Ord(AReverseMode)));
+end;
+
+procedure TBLPath.AddRoundRect(const ARoundRect: TBLRoundRect;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @ARoundRect, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddRoundRect(const ARoundRect: TBLRoundRect;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @ARoundRect, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddStrokedPath(const APath: IBLPath;
+  const AStrokeOptions: TBLStrokeOptions;
+  const AApproximationOptions: TBLApproximationOptions);
+begin
+  if (APath <> nil) then
+  begin
+    _BLCheck(blPathAddStrokedPath(@FHandle, APath.Handle, nil,
+      @AStrokeOptions.FHandle, @AApproximationOptions.FHandle));
+  end;
+end;
+
+procedure TBLPath.AddStrokedPath(const APath: IBLPath; const ARange: TBLRange;
+  const AStrokeOptions: TBLStrokeOptions;
+  const AApproximationOptions: TBLApproximationOptions);
+begin
+  if (APath <> nil) then
+  begin
+    _BLCheck(blPathAddStrokedPath(@FHandle, APath.Handle, @ARange,
+      @AStrokeOptions.FHandle, @AApproximationOptions.FHandle));
+  end;
+end;
+
+procedure TBLPath.AddTriangle(const ATriangle: TBLTriangle;
+  const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_TRIANGLE, @ATriangle, nil, Ord(ADirection)));
+end;
+
+procedure TBLPath.AddTriangle(const ATriangle: TBLTriangle;
+  const AMatrix: TBLMatrix2D; const ADirection: TBLGeometryDirection);
+begin
+  _BLCheck(blPathAddGeometry(@FHandle, BL_GEOMETRY_TYPE_TRIANGLE, @ATriangle, @AMatrix, Ord(ADirection)));
+end;
+
+procedure TBLPath.ArcQuadrantTo(const AX1, AY1, AX2, AY2: Double);
+begin
+  _BLCheck(blPathArcQuadrantTo(@FHandle, AX1, AY1, AX2, AY2));
+end;
+
+procedure TBLPath.ArcQuadrantTo(const AP1, AP2: TBLPoint);
+begin
+  _BLCheck(blPathArcQuadrantTo(@FHandle, AP1.FHandle.x, AP1.FHandle.y, AP2.FHandle.x, AP2.FHandle.y));
+end;
+
+procedure TBLPath.ArcTo(const AC, AR: TBLPoint; const AStart, ASweep: Double;
+  const AForceMoveTo: Boolean);
+begin
+  _BLCheck(blPathArcTo(@FHandle, AC.FHandle.x, AC.FHandle.y, AR.FHandle.x,
+    AR.FHandle.y, AStart, ASweep, AForceMoveTo));
+end;
+
+procedure TBLPath.ArcTo(const ACX, ACY, ARX, ARY, AStart, ASweep: Double;
+  const AForceMoveTo: Boolean);
+begin
+  _BLCheck(blPathArcTo(@FHandle, ACX, ACY, ARX, ARY, AStart, ASweep, AForceMoveTo));
+end;
+
+procedure TBLPath.Clear;
+begin
+  _BLCheck(blPathClear(@FHandle));
+end;
+
+function TBLPath.Clone: IBLPath;
+begin
+  Result := TBLPath.Create;
+  _BLCheck(blPathAssignDeep(Result.Handle, @FHandle));
+end;
+
+procedure TBLPath.Close;
+begin
+  _BLCheck(blPathClose(@FHandle));
+end;
+
+constructor TBLPath.Create;
+begin
+  inherited Create;
+  blPathInit(@FHandle);
+end;
+
+procedure TBLPath.CubicTo(const AX1, AY1, AX2, AY2, AX3, AY3: Double);
+begin
+  _BLCheck(blPathCubicTo(@FHandle, AX1, AY1, AX2, AY2, AX3, AY3));
+end;
+
+procedure TBLPath.CubicTo(const AP1, AP2, AP3: TBLPoint);
+begin
+  _BLCheck(blPathCubicTo(@FHandle, AP1.FHandle.x, AP1.FHandle.y, AP2.FHandle.x,
+    AP2.FHandle.y, AP3.FHandle.x, AP3.FHandle.y));
+end;
+
+destructor TBLPath.Destroy;
+begin
+  blPathDestroy(@FHandle);
+  inherited;
+end;
+
+procedure TBLPath.EllipticArcTo(const ARX, ARY, AXAxisRotation: Double;
+  const ALargeArcFlag, ASweepFlag: Boolean; const AX1, AY1: Double);
+begin
+  _BLCheck(blPathEllipticArcTo(@FHandle, ARX, ARY, AXAxisRotation, ALargeArcFlag,
+    ASweepFlag, AX1, AY1));
+end;
+
+procedure TBLPath.EllipticArcTo(const ARP: TBLPoint;
+  const AXAxisRotation: Double; const ALargeArcFlag, ASweepFlag: Boolean;
+  const AP1: TBLPoint);
+begin
+  _BLCheck(blPathEllipticArcTo(@FHandle, ARP.FHandle.x, ARP.FHandle.y,
+    AXAxisRotation, ALargeArcFlag, ASweepFlag, AP1.FHandle.x, AP1.FHandle.y));
+end;
+
+function TBLPath.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLPath) then
+    Result := blPathEquals(@FHandle, @TBLPath(Obj).FHandle)
+  else
+    Result := False;
+end;
+
+function TBLPath.Equals(const AOther: IBLPath): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := blPathEquals(@FHandle, AOther.Handle);
+end;
+
+procedure TBLPath.FitTo(const ARect: TBLRect; const AFitFlags: TBLFitFlags);
+begin
+  _BLCheck(blPathFitTo(@FHandle, nil, @ARect, Byte(AFitFlags)));
+end;
+
+procedure TBLPath.FitTo(const ARange: TBLRange; const ARect: TBLRect;
+  const AFitFlags: TBLFitFlags);
+begin
+  _BLCheck(blPathFitTo(@FHandle, @ARange, @ARect, Byte(AFitFlags)));
+end;
+
+function TBLPath.GetBoundingBox: TBLBox;
+begin
+  _BLCheck(blPathGetBoundingBox(@FHandle, @Result));
+end;
+
+function TBLPath.GetCapacity: Integer;
+begin
+  Result := FHandle.impl.capacity;
+end;
+
+function TBLPath.GetClosestVertex(const AP: TBLPoint;
+  const AMaxDistance: Double): Integer;
+var
+  Index: NativeUInt;
+  ActualDistance: Double;
+begin
+  _BLCheck(blPathGetClosestVertex(@FHandle, @AP, AMaxDistance, @Index, @ActualDistance));
+  Result := Index;
+end;
+
+function TBLPath.GetClosestVertex(const AP: TBLPoint;
+  const AMaxDistance: Double; out AActualDistance: Double): Integer;
+var
+  Index: NativeUInt;
+begin
+  _BLCheck(blPathGetClosestVertex(@FHandle, @AP, AMaxDistance, @Index, @AActualDistance));
+  Result := Index;
+end;
+
+function TBLPath.GetCommandData: PBLPathCmd;
+begin
+  Result := Pointer(FHandle.impl.commandData);
+end;
+
+function TBLPath.GetCommandDataEnd: PBLPathCmd;
+begin
+  Result := Pointer(FHandle.impl.commandData + FHandle.impl.size);
+end;
+
+function TBLPath.GetControlBox: TBLBox;
+begin
+  _BLCheck(blPathGetControlBox(@FHandle, @Result));
+end;
+
+function TBLPath.GetCount: Integer;
+begin
+  Result := FHandle.impl.size;
+end;
+
+function TBLPath.GetFigureRange(const AIndex: Integer): TBLRange;
+begin
+  _BLCheck(blPathGetFigureRange(@FHandle, AIndex, @Result));
+end;
+
+function TBLPath.GetHandle: PBLPathCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLPath.GetInfoFlags: TBLPathFlags;
+begin
+  _BLCheck(blPathGetInfoFlags(@FHandle, @Result));
+end;
+
+function TBLPath.GetIsEmpty: Boolean;
+begin
+  Result := (FHandle.impl.size = 0);
+end;
+
+function TBLPath.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLPath.GetLastVertex: TBLPoint;
+begin
+  _BLCheck(blPathGetLastVertex(@FHandle, @Result));
+end;
+
+function TBLPath.GetVertexData: PBLPoint;
+begin
+  Result := Pointer(FHandle.impl.vertexData);
+end;
+
+function TBLPath.GetVertexDataEnd: PBLPoint;
+begin
+  Result := Pointer(FHandle.impl.vertexData + FHandle.impl.size);
+end;
+
+function TBLPath.GetView: TBLPathView;
+begin
+  Result.FHandle := FHandle.impl.view;
+end;
+
+function TBLPath.HitTest(const AP: TBLPoint;
+  const AFillRule: TBLFillRule): TBLHitTest;
+begin
+  Result := TBLHitTest(blPathHitTest(@FHandle, @AP, Ord(AFillRule)));
+end;
+
+procedure TBLPath.LineTo(const AX1, AY1: Double);
+begin
+  _BLCheck(blPathLineTo(@FHandle, AX1, AY1));
+end;
+
+procedure TBLPath.LineTo(const AP1: TBLPoint);
+begin
+  _BLCheck(blPathLineTo(@FHandle, AP1.FHandle.x, AP1.FHandle.y));
+end;
+
+procedure TBLPath.MoveTo(const AX0, AY0: Double);
+begin
+  _BLCheck(blPathMoveTo(@FHandle, AX0, AY0));
+end;
+
+procedure TBLPath.MoveTo(const AP0: TBLPoint);
+begin
+  _BLCheck(blPathMoveTo(@FHandle, AP0.FHandle.x, AP0.FHandle.y));
+end;
+
+procedure TBLPath.PolyTo(const APoly: TArray<TBLPoint>);
+begin
+  _BLCheck(blPathPolyTo(@FHandle, Pointer(APoly), Length(APoly)));
+end;
+
+procedure TBLPath.PolyTo(const APoly: PBLPoint; const ACount: Integer);
+begin
+  _BLCheck(blPathPolyTo(@FHandle, _PBLPoint(APoly), ACount));
+end;
+
+procedure TBLPath.QuadTo(const AP1, AP2: TBLPoint);
+begin
+  _BLCheck(blPathQuadTo(@FHandle, AP1.FHandle.x, AP1.FHandle.y, AP2.FHandle.x, AP2.FHandle.y));
+end;
+
+procedure TBLPath.QuadTo(const AX1, AY1, AX2, AY2: Double);
+begin
+  _BLCheck(blPathQuadTo(@FHandle, AX1, AY1, AX2, AY2));
+end;
+
+procedure TBLPath.RemoveRange(const ARange: TBLRange);
+begin
+  _BLCheck(blPathRemoveRange(@FHandle, @ARange.FHandle));
+end;
+
+procedure TBLPath.Reserve(const ACount: Integer);
+begin
+  _BLCheck(blPathReserve(@FHandle, ACount));
+end;
+
+procedure TBLPath.Reset;
+begin
+  _BLCheck(blPathReset(@FHandle));
+end;
+
+procedure TBLPath.SetVertexAt(const AIndex: Integer; const ACmd: TBLPathCmd;
+  const AX, AY: Double; const APreserve: Boolean);
+const
+  FLAGS: array [Boolean] of Cardinal = (0, BL_PATH_CMD_PRESERVE);
+begin
+  _BLCheck(blPathSetVertexAt(@FHandle, AIndex, Byte(ACmd) or FLAGS[APreserve], AX, AY));
+end;
+
+procedure TBLPath.SetVertexAt(const AIndex: Integer; const ACmd: TBLPathCmd;
+  const APt: TBLPoint; const APreserve: Boolean);
+const
+  FLAGS: array [Boolean] of Cardinal = (0, BL_PATH_CMD_PRESERVE);
+begin
+  _BLCheck(blPathSetVertexAt(@FHandle, AIndex, Byte(ACmd) or FLAGS[APreserve],
+    APt.FHandle.x, APt.FHandle.y));
+end;
+
+procedure TBLPath.Shrink;
+begin
+  _BLCheck(blPathShrink(@FHandle));
+end;
+
+procedure TBLPath.SmoothCubicTo(const AX2, AY2, AX3, AY3: Double);
+begin
+  _BLCheck(blPathSmoothCubicTo(@FHandle, AX2, AY2, AX3, AY3));
+end;
+
+procedure TBLPath.SmoothCubicTo(const AP2, AP3: TBLPoint);
+begin
+  _BLCheck(blPathSmoothCubicTo(@FHandle, AP2.FHandle.x, AP2.FHandle.y, AP3.FHandle.x, AP3.FHandle.y));
+end;
+
+procedure TBLPath.SmoothQuadTo(const AP2: TBLPoint);
+begin
+  _BLCheck(blPathSmoothQuadTo(@FHandle, AP2.FHandle.x, AP2.FHandle.y));
+end;
+
+procedure TBLPath.SmoothQuadTo(const AX2, AY2: Double);
+begin
+  _BLCheck(blPathSmoothQuadTo(@FHandle, AX2, AY2));
+end;
+
+procedure TBLPath.Transform(const ARange: TBLRange; const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blPathTransform(@FHandle, @ARange, @AMatrix));
+end;
+
+procedure TBLPath.Transform(const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blPathTransform(@FHandle, nil, @AMatrix));
+end;
+
+procedure TBLPath.Translate(const ARange: TBLRange; const AP: TBLPoint);
+begin
+  _BLCheck(blPathTranslate(@FHandle, @ARange, @AP));
+end;
+
+procedure TBLPath.Translate(const AP: TBLPoint);
+begin
+  _BLCheck(blPathTranslate(@FHandle, nil, @AP));
+end;
+
+{$ENDREGION 'Path'}
+
+{$REGION 'Format'}
+
+{ TBLFormatInfo }
+
+class operator TBLFormatInfo.Equal(const ALeft, ARight: TBLFormatInfo): Boolean;
+begin
+  Result := CompareMem(@ALeft, @ARight, SizeOf(TBLFormatInfo));
+end;
+
+function TBLFormatInfo.GetFlags: TBLFormatFlags;
+begin
+  Cardinal(Result) := FHandle.flags;
+end;
+
+function TBLFormatInfo.GetPalette: PBLRgba32;
+begin
+  Result := Pointer(FHandle.palette);
+end;
+
+class operator TBLFormatInfo.NotEqual(const ALeft,
+  ARight: TBLFormatInfo): Boolean;
+begin
+  Result := not CompareMem(@ALeft, @ARight, SizeOf(TBLFormatInfo));
+end;
+
+procedure TBLFormatInfo.Query(const AFormat: TBLFormat);
+begin
+  _BLCheck(blFormatInfoQuery(@FHandle, Ord(AFormat)));
+end;
+
+procedure TBLFormatInfo.Reset(const ADepth: Integer;
+  const AFlags: TBLFormatFlags; const ARSize, AGSize, ABSize, AASize, ARShift,
+  AGShift, ABShift, AAShift: Byte);
+begin
+  FHandle.depth := ADepth;
+  FHandle.flags := Cardinal(AFlags);
+  FHandle.rSize := ARSize;
+  FHandle.gSize := AGSize;
+  FHandle.bSize := ABSize;
+  FHandle.aSize := AASize;
+  FHandle.rShift := ARShift;
+  FHandle.gShift := AGShift;
+  FHandle.bShift := ABShift;
+  FHandle.aShift := AAShift;
+end;
+
+procedure TBLFormatInfo.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLFormatInfo.Sanitize;
+begin
+  _BLCheck(blFormatInfoSanitize(@FHandle));
+end;
+
+procedure TBLFormatInfo.SetFlags(const AValue: TBLFormatFlags);
+begin
+  FHandle.flags := Cardinal(AValue);
+end;
+
+procedure TBLFormatInfo.SetShifts(const ARShift, AGShift, ABShift,
+  AAShift: Byte);
+begin
+  FHandle.rShift := ARShift;
+  FHandle.gShift := AGShift;
+  FHandle.bShift := ABShift;
+  FHandle.aShift := AAShift;
+end;
+
+procedure TBLFormatInfo.SetSizes(const ARSize, AGSize, ABSize, AASize: Byte);
+begin
+  FHandle.rSize := ARSize;
+  FHandle.gSize := AGSize;
+  FHandle.bSize := ABSize;
+  FHandle.aSize := AASize;
+end;
+
+{ _TBLFormatHelper }
+
+function _TBLFormatHelper.GetInfo: TBLFormatInfo;
+begin
+  _BLCheck(blFormatInfoQuery(@Result.FHandle, Ord(Self)));
+end;
+
+{$ENDREGION 'Format'}
+
+{$REGION 'Image'}
+
+{ TBLImageData }
+
+function TBLImageData.GetFlags: TBLFormatFlags;
+begin
+  Cardinal(Result) := FHandle.flags;
+end;
+
+function TBLImageData.GetFormat: TBLFormat;
+begin
+  Byte(Result) := FHandle.format;
+end;
+
+function TBLImageData.GetSize: TBLSizeI;
+begin
+  Result.FHandle := FHandle.size;
+end;
+
+procedure TBLImageData.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLImageData.SetFlags(const AValue: TBLFormatFlags);
+begin
+  FHandle.flags := Cardinal(AValue);
+end;
+
+procedure TBLImageData.SetFormat(const AValue: TBLFormat);
+begin
+  FHandle.format := Ord(AValue);
+end;
+
+procedure TBLImageData.SetSize(const AValue: TBLSizeI);
+begin
+  FHandle.size := AValue.FHandle;
+end;
+
+{ TBLImageInfo }
+
+function TBLImageInfo.GetCompression: String;
+begin
+  Result := String(UTF8String(FHandle.compression));
+end;
+
+function TBLImageInfo.GetDensity: TBLSize;
+begin
+  Result.FHandle := FHandle.density;
+end;
+
+function TBLImageInfo.GetDepth: Integer;
+begin
+  Result := FHandle.depth;
+end;
+
+function TBLImageInfo.GetFlags: TBLFormatFlags;
+begin
+  Cardinal(Result) := FHandle.flags;
+end;
+
+function TBLImageInfo.GetFormat: String;
+begin
+  Result := String(UTF8String(FHandle.format));
+end;
+
+function TBLImageInfo.GetFrameCount: Integer;
+begin
+  Result := FHandle.frameCount;
+end;
+
+function TBLImageInfo.GetPlaneCount: Integer;
+begin
+  Result := FHandle.planeCount;
+end;
+
+function TBLImageInfo.GetSize: TBLSizeI;
+begin
+  Result.FHandle := FHandle.size;
+end;
+
+procedure TBLImageInfo.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+{ TBLImageScaleOptions }
+
+function TBLImageScaleOptions.GetUserFunc: TBLImageScaleUserFunc;
+begin
+  Result := TBLImageScaleUserFunc(FHandle.userFunc);
+end;
+
+procedure TBLImageScaleOptions.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLImageScaleOptions.ResetToDefaults;
+begin
+  FHandle.userFunc := nil;
+  FHandle.userData := nil;
+  FHandle.radius := 2;
+  FHandle.mitchell.b := 1 / 3;
+  FHandle.mitchell.c := 1 / 3;
+  FHandle.data[2] := 0;
+end;
+
+procedure TBLImageScaleOptions.SetUserFunc(const AValue: TBLImageScaleUserFunc);
+begin
+  TBLImageScaleUserFunc(FHandle.userFunc) := AValue;
+end;
+
+{ TBLImage }
+
+constructor TBLImage.Create;
+begin
+  inherited Create;
+  blImageInit(@FHandle);
+end;
+
+function TBLImage.Clone: IBLImage;
+begin
+  Result := TBLImage.Create;
+  _BLCheck(blImageAssignDeep(Result.Handle, @FHandle));
+end;
+
+procedure TBLImage.Convert(const AFormat: TBLFormat);
+begin
+  _BLCheck(blImageConvert(@FHandle, Ord(AFormat)));
+end;
+
+constructor TBLImage.Create(const AWidth, AHeight: Integer;
+  const AFormat: TBLFormat);
+begin
+  inherited Create;
+  _BLCheck(blImageInitAs(@FHandle, AWidth, AHeight, Ord(AFormat)));
+end;
+
+constructor TBLImage.Create(const AHandle: BLImageCore;
+  const AIsReference: Boolean);
+begin
+  inherited Create;
+  FHandle := AHandle;
+  FIsReference := AIsReference;
+end;
+
+destructor TBLImage.Destroy;
+begin
+  if (not FIsReference) then
+    blImageDestroy(@FHandle);
+  inherited;
+end;
+
+class procedure TBLImage.DoDestroy(impl, destroyData: Pointer);
+var
+  Data: PDestroyData absolute destroyData;
+begin
+  if (Data <> nil) then
+  begin
+    Data.Event(Data.Image);
+    FreeMem(Data);
+  end;
+end;
+
+function TBLImage.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLImage) then
+    Result := blImageEquals(@FHandle, @TBLImage(Obj).FHandle)
+  else
+    Result := False;
+end;
+
+function TBLImage.Equals(const AOther: IBLImage): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := blImageEquals(@FHandle, AOther.Handle);
+end;
+
+procedure TBLImage.GetData(out AData: TBLImageData);
+begin
+  _BLCheck(blImageGetData(@FHandle, @AData.FHandle));
+end;
+
+function TBLImage.GetFormat: TBLFormat;
+begin
+  Result := TBLFormat(FHandle.impl.format);
+end;
+
+function TBLImage.GetHandle: PBLImageCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLImage.GetHeight: Integer;
+begin
+  Result := FHandle.impl.size.h;
+end;
+
+function TBLImage.GetIsEmpty: Boolean;
+begin
+  Result := (FHandle.impl.format = BL_FORMAT_NONE);
+end;
+
+function TBLImage.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLImage.GetSize: TBLSizeI;
+begin
+  Result := TBLSizeI(FHandle.impl.size);
+end;
+
+function TBLImage.GetWidth: Integer;
+begin
+  Result := FHandle.impl.size.w;
+end;
+
+procedure TBLImage.Initialize(const AWidth, AHeight: Integer;
+  const AFormat: TBLFormat);
+begin
+  _BLCheck(blImageCreate(@FHandle, AWidth, AHeight, Ord(AFormat)));
+end;
+
+procedure TBLImage.InitializeFromData(const AWidth, AHeight: Integer;
+  const AFormat: TBLFormat; const APixelData: Pointer; const AStride: Integer;
+  const AOnDestroy: TBLImageDestroyEvent);
+var
+  DestroyFunc: BLDestroyImplFunc;
+  DestroyData: PDestroyData;
+begin
+  if Assigned(AOnDestroy) then
+  begin
+    DestroyFunc := DoDestroy;
+    GetMem(DestroyData, SizeOf(TDestroyData));
+    DestroyData.Image := Self;
+    DestroyData.Event := AOnDestroy;
+  end
+  else
+  begin
+    DestroyFunc := nil;
+    DestroyData := nil;
+  end;
+  _BLCheck(blImageCreateFromData(@FHandle, AWidth, AHeight, Ord(AFormat),
+    APixelData, AStride, DestroyFunc, DestroyData));
+end;
+
+procedure TBLImage.MakeMutable(out AData: TBLImageData);
+begin
+  _BLCheck(blImageMakeMutable(@FHandle, @AData.FHandle));
+end;
+
+procedure TBLImage.MakeMutable;
+var
+  Unused: TBLImageData;
+begin
+  _BLCheck(blImageMakeMutable(@FHandle, @Unused.FHandle));
+end;
+
+procedure TBLImage.ReadFromData(const AData: TBytes);
+begin
+  ReadFromData(Pointer(AData), Length(AData), nil);
+end;
+
+procedure TBLImage.ReadFromData(const AData: TBytes;
+  const ACodecs: TArray<IBLImageCodec>);
+begin
+  ReadFromData(Pointer(AData), Length(AData), ACodecs);
+end;
+
+procedure TBLImage.ReadFromData(const AData: Pointer; const ASize: Integer);
+begin
+  _BLCheck(blImageReadFromData(@FHandle, AData, ASize, nil));
+end;
+
+procedure TBLImage.ReadFromData(const AData: Pointer; const ASize: Integer;
+  const ACodecs: TArray<IBLImageCodec>);
+var
+  CodecHandles: TArray<BLImageCodecCore>;
+  Codecs: IBLArray;
+  I: Integer;
+begin
+  SetLength(CodecHandles, Length(ACodecs));
+  for I := 0 to Length(CodecHandles) - 1 do
+    CodecHandles[I] := ACodecs[I].Handle^;
+  Codecs := TBLUtils.ArrayToBLArray<BLImageCodecCore>(CodecHandles);
+
+  _BLCheck(blImageReadFromData(@FHandle, AData, ASize, Codecs.Handle));
+end;
+
+procedure TBLImage.ReadFromData(const AView: TBLArrayView<Byte>);
+begin
+  ReadFromData(AView.Data, AView.Length, nil);
+end;
+
+procedure TBLImage.ReadFromData(const AView: TBLArrayView<Byte>;
+  const ACodecs: TArray<IBLImageCodec>);
+begin
+  ReadFromData(AView.Data, AView.Length, ACodecs);
+end;
+
+procedure TBLImage.ReadFromFile(const AFilename: String);
+begin
+  _BLCheck(blImageReadFromFile(@FHandle, MarshaledAString(UTF8String(AFilename)), nil));
+end;
+
+procedure TBLImage.ReadFromFile(const AFilename: String;
+  const ACodecs: TArray<IBLImageCodec>);
+var
+  CodecHandles: TArray<BLImageCodecCore>;
+  Codecs: IBLArray;
+  I: Integer;
+begin
+  SetLength(CodecHandles, Length(ACodecs));
+  for I := 0 to Length(CodecHandles) - 1 do
+    CodecHandles[I] := ACodecs[I].Handle^;
+  Codecs := TBLUtils.ArrayToBLArray<BLImageCodecCore>(CodecHandles);
+
+  _BLCheck(blImageReadFromFile(@FHandle, MarshaledAString(UTF8String(AFilename)), Codecs.Handle));
+end;
+
+procedure TBLImage.Reset;
+begin
+  _BLCheck(blImageReset(@FHandle));
+end;
+
+class procedure TBLImage.Scale(const ASrc, ADst: IBLImage;
+  const ASize: TBLSizeI; const AFilter: TBLImageScaleFilter);
+begin
+  if (ASrc <> nil) then
+    ASrc.ScaleTo(ADst, ASize, AFilter);
+end;
+
+class procedure TBLImage.Scale(const ASrc, ADst: IBLImage;
+  const ASize: TBLSizeI; const AFilter: TBLImageScaleFilter;
+  const AOptions: TBLImageScaleOptions);
+begin
+  if (ASrc <> nil) then
+    ASrc.ScaleTo(ADst, ASize, AFilter, AOptions);
+end;
+
+procedure TBLImage.ScaleTo(const ADest: IBLImage; const ASize: TBLSizeI;
+  const AFilter: TBLImageScaleFilter);
+begin
+  if (ADest <> nil) then
+    _BLCheck(blImageScale(ADest.Handle, @FHandle, @ASize, Ord(AFilter), nil));
+end;
+
+procedure TBLImage.ScaleTo(const ADest: IBLImage; const ASize: TBLSizeI;
+  const AFilter: TBLImageScaleFilter; const AOptions: TBLImageScaleOptions);
+begin
+  if (ADest <> nil) then
+    _BLCheck(blImageScale(ADest.Handle, @FHandle, @ASize, Ord(AFilter), @AOptions.FHandle));
+end;
+
+function TBLImage.WriteToData(const ACodec: IBLImageCodec): TBytes;
+var
+  Codec: PBLImageCodecCore;
+  Data: IBLArray;
+begin
+  if (ACodec = nil) then
+    Codec := nil
+  else
+    Codec := ACodec.Handle;
+
+  Data := TBLUtils.CreateBLArray<Byte>;
+  _BLCheck(blImageWriteToData(@FHandle, Data.Handle, Codec));
+  Result := TBLUtils.BLArrayToArray<Byte>(Data);
+end;
+
+procedure TBLImage.WriteToFile(const AFilename: String);
+begin
+  _BLCheck(blImageWriteToFile(@FHandle, MarshaledAString(UTF8String(AFilename)), nil));
+end;
+
+procedure TBLImage.WriteToFile(const AFilename: String;
+  const ACodec: IBLImageCodec);
+var
+  Codec: PBLImageCodecCore;
+begin
+  if (ACodec = nil) then
+    Codec := nil
+  else
+    Codec := ACodec.Handle;
+
+  _BLCheck(blImageWriteToFile(@FHandle, MarshaledAString(UTF8String(AFilename)), Codec));
+end;
+
+{$ENDREGION 'Image'}
+
+{$REGION 'Image Codec'}
+
+{ TBLImageDecoder }
+
+constructor TBLImageDecoder.Create;
+begin
+  inherited Create;
+  blImageDecoderInit(@FHandle);
+end;
+
+destructor TBLImageDecoder.Destroy;
+begin
+  blImageDecoderDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLImageDecoder.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLImageDecoder) then
+    Result := (FHandle.impl = @TBLImageDecoder(Obj).FHandle.impl)
+  else
+    Result := False;
+end;
+
+function TBLImageDecoder.Equals(const AOther: IBLImageDecoder): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := (FHandle.impl = AOther.Handle.impl);
+end;
+
+function TBLImageDecoder.GetBufferIndex: NativeInt;
+begin
+  Result := FHandle.impl.bufferIndex;
+end;
+
+function TBLImageDecoder.GetFrameIndex: Integer;
+begin
+  Result := FHandle.impl.frameIndex;
+end;
+
+function TBLImageDecoder.GetHandle: PBLImageDecoderCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLImageDecoder.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLImageDecoder.GetLastResult: TBLResultCode;
+begin
+  Result := TBLResultCode(FHandle.impl.lastResult);
+end;
+
+function TBLImageDecoder.ReadFrame(const ABuffer: Pointer;
+  const ASize: Integer): IBLImage;
+begin
+  Result := TBLImage.Create;
+  _BLCheck(blImageDecoderReadFrame(@FHandle, Result.Handle, ABuffer, ASize));
+end;
+
+function TBLImageDecoder.ReadFrame(const ABuffer: TBLArrayView<Byte>): IBLImage;
+begin
+  Result := TBLImage.Create;
+  _BLCheck(blImageDecoderReadFrame(@FHandle, Result.Handle,
+    ABuffer.FHandle.data, ABuffer.FHandle.size));
+end;
+
+function TBLImageDecoder.ReadFrame(const ABuffer: TBytes): IBLImage;
+begin
+  Result := TBLImage.Create;
+  _BLCheck(blImageDecoderReadFrame(@FHandle, Result.Handle,
+    Pointer(ABuffer), Length(ABuffer)));
+end;
+
+procedure TBLImageDecoder.ReadInfo(const ABuffer: Pointer; const ASize: Integer;
+  out AInfo: TBLImageInfo);
+begin
+  _BLCheck(blImageDecoderReadInfo(@FHandle, @AInfo.FHandle, ABuffer, ASize));
+end;
+
+procedure TBLImageDecoder.ReadInfo(const ABuffer: TBLArrayView<Byte>;
+  out AInfo: TBLImageInfo);
+begin
+  _BLCheck(blImageDecoderReadInfo(@FHandle, @AInfo.FHandle,
+    ABuffer.FHandle.data, ABuffer.FHandle.size));
+end;
+
+procedure TBLImageDecoder.ReadInfo(const ABuffer: TBytes;
+  out AInfo: TBLImageInfo);
+begin
+  _BLCheck(blImageDecoderReadInfo(@FHandle, @AInfo.FHandle,
+    Pointer(ABuffer), Length(ABuffer)));
+end;
+
+procedure TBLImageDecoder.Reset;
+begin
+  _BLCheck(blImageDecoderReset(@FHandle));
+end;
+
+procedure TBLImageDecoder.Restart;
+begin
+  _BLCheck(blImageDecoderRestart(@FHandle));
+end;
+
+{ TBLImageEncoder }
+
+constructor TBLImageEncoder.Create;
+begin
+  inherited Create;
+  blImageEncoderInit(@FHandle);
+end;
+
+destructor TBLImageEncoder.Destroy;
+begin
+  blImageEncoderDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLImageEncoder.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLImageEncoder) then
+    Result := (FHandle.impl = @TBLImageEncoder(Obj).FHandle.impl)
+  else
+    Result := False;
+end;
+
+function TBLImageEncoder.Equals(const AOther: IBLImageEncoder): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := (FHandle.impl = AOther.Handle.impl);
+end;
+
+function TBLImageEncoder.GetBufferIndex: NativeInt;
+begin
+  Result := FHandle.impl.bufferIndex;
+end;
+
+function TBLImageEncoder.GetFrameIndex: Integer;
+begin
+  Result := FHandle.impl.frameIndex;
+end;
+
+function TBLImageEncoder.GetHandle: PBLImageEncoderCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLImageEncoder.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLImageEncoder.GetLastResult: TBLResultCode;
+begin
+  Result := TBLResultCode(FHandle.impl.lastResult);
+end;
+
+procedure TBLImageEncoder.Reset;
+begin
+  _BLCheck(blImageEncoderReset(@FHandle));
+end;
+
+procedure TBLImageEncoder.Restart;
+begin
+  _BLCheck(blImageEncoderRestart(@FHandle));
+end;
+
+function TBLImageEncoder.WriteFrame(const AImage: IBLImage): TBytes;
+var
+  Dest: IBLArray;
+begin
+  if (AImage <> nil) then
+  begin
+    Dest := TBLUtils.CreateBLArray<Byte>;
+    _BLCheck(blImageEncoderWriteFrame(@FHandle, Dest.Handle, AImage.Handle));
+    Result := TBLUtils.BLArrayToArray<Byte>(Dest);
+  end;
+end;
+
+{ TBLImageCodec }
+
+class procedure TBLImageCodec.AddToBuiltIn(const ACodec: IBLImageCodec);
+begin
+  if (ACodec <> nil) then
+    _BLCheck(blImageCodecAddToBuiltIn(ACodec.Handle));
+end;
+
+constructor TBLImageCodec.Create;
+begin
+  inherited Create;
+  blImageCodecInit(@FHandle);
+end;
+
+constructor TBLImageCodec.Create(const AHandle: BLImageCodecCore;
+  const AIsReference: Boolean);
+begin
+  inherited Create;
+  FHandle := AHandle;
+  FIsReference := AIsReference;
+end;
+
+destructor TBLImageCodec.Destroy;
+begin
+  if (not FIsReference) then
+    blImageCodecDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLImageCodec.Equals(const AOther: IBLImageCodec): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := (FHandle.impl = AOther.Handle.impl);
+end;
+
+function TBLImageCodec.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLImageCodec) then
+    Result := (FHandle.impl = @TBLImageCodec(Obj).FHandle.impl)
+  else
+    Result := False;
+end;
+
+function TBLImageCodec.FindByData(const AData: TBytes;
+  const ACodecs: TArray<IBLImageCodec>): Boolean;
+begin
+  Result := FindByData(Pointer(AData), Length(AData), ACodecs);
+end;
+
+function TBLImageCodec.FindByExtension(const AExt: String;
+  const ACodecs: TArray<IBLImageCodec>): Boolean;
+var
+  CodecHandles: TArray<BLImageCodecCore>;
+  CodecArray: IBLArray;
+  Codecs: PBLArrayCore;
+  Ext: UTF8String;
+  Res: BLResultCode;
+  I: Integer;
+begin
+  if Assigned(ACodecs) then
+  begin
+    SetLength(CodecHandles, Length(ACodecs));
+    for I := 0 to Length(CodecHandles) - 1 do
+      CodecHandles[I] := ACodecs[I].Handle^;
+    CodecArray := TBLUtils.ArrayToBLArray<BLImageCodecCore>(CodecHandles);
+    Codecs := CodecArray.Handle;
+  end
+  else
+    Codecs := nil;
+
+  Ext := UTF8String(AExt);
+  Res := blImageCodecFindByExtension(@FHandle, MarshaledAString(Ext), Length(Ext), Codecs);
+  Result := (Res = BL_SUCCESS);
+  if (Res <> BL_ERROR_IMAGE_NO_MATCHING_CODEC) then
+    _BLCheck(Res);
+end;
+
+function TBLImageCodec.FindByExtension(const AExt: String): Boolean;
+var
+  Ext: UTF8String;
+  Res: BLResultCode;
+begin
+  Ext := UTF8String(AExt);
+  Res := blImageCodecFindByExtension(@FHandle, MarshaledAString(Ext), Length(Ext), nil);
+  Result := (Res = BL_SUCCESS);
+  if (Res <> BL_ERROR_IMAGE_NO_MATCHING_CODEC) then
+    _BLCheck(Res);
+end;
+
+function TBLImageCodec.FindByData(const AData: Pointer;
+  const ASize: Integer): Boolean;
+var
+  Res: BLResultCode;
+begin
+  Res := blImageCodecFindByData(@FHandle, AData, ASize, nil);
+  Result := (Res = BL_SUCCESS);
+  if (Res <> BL_ERROR_IMAGE_NO_MATCHING_CODEC) then
+    _BLCheck(Res);
+end;
+
+function TBLImageCodec.FindByData(const AData: Pointer; const ASize: Integer;
+  const ACodecs: TArray<IBLImageCodec>): Boolean;
+var
+  CodecHandles: TArray<BLImageCodecCore>;
+  CodecArray: IBLArray;
+  Codecs: PBLArrayCore;
+  Res: BLResultCode;
+  I: Integer;
+begin
+  if Assigned(ACodecs) then
+  begin
+    SetLength(CodecHandles, Length(ACodecs));
+    for I := 0 to Length(CodecHandles) - 1 do
+      CodecHandles[I] := ACodecs[I].Handle^;
+    CodecArray := TBLUtils.ArrayToBLArray<BLImageCodecCore>(CodecHandles);
+    Codecs := CodecArray.Handle;
+  end
+  else
+    Codecs := nil;
+
+  Res := blImageCodecFindByData(@FHandle, AData, ASize, Codecs);
+  Result := (Res = BL_SUCCESS);
+  if (Res <> BL_ERROR_IMAGE_NO_MATCHING_CODEC) then
+    _BLCheck(Res);
+end;
+
+function TBLImageCodec.FindByData(const AData: TBytes): Boolean;
+var
+  Res: BLResultCode;
+begin
+  Res := blImageCodecFindByData(@FHandle, Pointer(AData), Length(AData), nil);
+  Result := (Res = BL_SUCCESS);
+  if (Res <> BL_ERROR_IMAGE_NO_MATCHING_CODEC) then
+    _BLCheck(Res);
+end;
+
+function TBLImageCodec.FindByName(const AName: String;
+  const ACodecs: TArray<IBLImageCodec>): Boolean;
+var
+  CodecHandles: TArray<BLImageCodecCore>;
+  CodecArray: IBLArray;
+  Codecs: PBLArrayCore;
+  Name: UTF8String;
+  Res: BLResultCode;
+  I: Integer;
+begin
+  if Assigned(ACodecs) then
+  begin
+    SetLength(CodecHandles, Length(ACodecs));
+    for I := 0 to Length(CodecHandles) - 1 do
+      CodecHandles[I] := ACodecs[I].Handle^;
+    CodecArray := TBLUtils.ArrayToBLArray<BLImageCodecCore>(CodecHandles);
+    Codecs := CodecArray.Handle;
+  end
+  else
+    Codecs := nil;
+
+  Name := UTF8String(AName);
+  Res := blImageCodecFindByName(@FHandle, MarshaledAString(Name), Length(Name), Codecs);
+  Result := (Res = BL_SUCCESS);
+  if (Res <> BL_ERROR_IMAGE_NO_MATCHING_CODEC) then
+    _BLCheck(Res);
+end;
+
+function TBLImageCodec.FindByName(const AName: String): Boolean;
+var
+  Name: UTF8String;
+  Res: BLResultCode;
+begin
+  Name := UTF8String(AName);
+  Res := blImageCodecFindByName(@FHandle, MarshaledAString(Name), Length(Name), nil);
+  Result := (Res = BL_SUCCESS);
+  if (Res <> BL_ERROR_IMAGE_NO_MATCHING_CODEC) then
+    _BLCheck(Res);
+end;
+
+class function TBLImageCodec.GetBuiltInCodecs: TArray<IBLImageCodec>;
+var
+  CodecArray: IBLArray;
+  CodecHandles: TArray<BLImageCodecCore>;
+  I: Integer;
+begin
+  CodecArray := TBLUtils.CreateBLArray<BLImageCodecCore>;
+  _BLCheck(blImageCodecArrayInitBuiltInCodecs(CodecArray.Handle));
+  CodecHandles := TBLUtils.BLArrayToArray<BLImageCodecCore>(CodecArray);
+
+  SetLength(Result, Length(CodecHandles));
+  for I := 0 to Length(Result) - 1 do
+    Result[I] := TBLImageCodec.Create(CodecHandles[I], True);
+end;
+
+function TBLImageCodec.GetExtensions: String;
+begin
+  Result := String(UTF8String(FHandle.impl.extensions));
+end;
+
+function TBLImageCodec.GetFeatures: TBLImageCodecFeatures;
+begin
+  Result := TBLImageCodecFeatures(FHandle.impl.features);
+end;
+
+function TBLImageCodec.GetHandle: PBLImageCodecCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLImageCodec.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLImageCodec.GetMimeType: String;
+begin
+  Result := String(UTF8String(FHandle.impl.mimeType));
+end;
+
+function TBLImageCodec.GetName: String;
+begin
+  Result := String(UTF8String(FHandle.impl.name));
+end;
+
+function TBLImageCodec.GetVendor: String;
+begin
+  Result := String(UTF8String(FHandle.impl.vendor));
+end;
+
+function TBLImageCodec.HasFeature(
+  const AFeature: TBLImageCodecFeature): Boolean;
+begin
+  Result := ((FHandle.impl.features and Ord(AFeature)) <> 0);
+end;
+
+function TBLImageCodec.InspectData(const ABuffer: TBytes): Cardinal;
+begin
+  Result := blImageCodecInspectData(@FHandle, Pointer(ABuffer), Length(ABuffer));
+end;
+
+function TBLImageCodec.InspectData(const ABuffer: TBLArrayView<Byte>): Cardinal;
+begin
+  Result := blImageCodecInspectData(@FHandle, ABuffer.FHandle.data, ABuffer.FHandle.size);
+end;
+
+function TBLImageCodec.InspectData(const ABuffer: Pointer;
+  const ASize: Integer): Cardinal;
+begin
+  Result := blImageCodecInspectData(@FHandle, ABuffer, ASize);
+end;
+
+class procedure TBLImageCodec.RemoveFromBuiltIn(const ACodec: IBLImageCodec);
+begin
+  if (ACodec <> nil) then
+    _BLCheck(blImageCodecRemoveFromBuiltIn(ACodec.Handle));
+end;
+
+procedure TBLImageCodec.Reset;
+begin
+  _BLCheck(blImageCodecReset(@FHandle));
+end;
+
+{$ENDREGION 'Image Codec'}
+
+{$REGION 'Pattern'}
+
+{ TBLPattern }
+
+constructor TBLPattern.Create;
+begin
+  inherited;
+  blPatternInit(@FHandle);
+end;
+
+constructor TBLPattern.Create(const AImage: IBLImage;
+  const AExtendMode: TBLExtendMode);
+begin
+  inherited Create;
+  FImage := AImage;
+  if (AImage = nil) then
+    blPatternInit(@FHandle)
+  else
+    _BLCheck(blPatternInitAs(@FHandle, AImage.Handle, nil, Ord(AExtendMode), nil));
+end;
+
+constructor TBLPattern.Create(const AImage: IBLImage;
+  const AExtendMode: TBLExtendMode; const AMatrix: TBLMatrix2D);
+begin
+  inherited Create;
+  FImage := AImage;
+  if (AImage = nil) then
+    blPatternInit(@FHandle)
+  else
+    _BLCheck(blPatternInitAs(@FHandle, AImage.Handle, nil, Ord(AExtendMode), @AMatrix));
+end;
+
+constructor TBLPattern.Create(const AImage: IBLImage; const AArea: TBLRectI;
+  const AExtendMode: TBLExtendMode);
+begin
+  inherited Create;
+  FImage := AImage;
+  if (AImage = nil) then
+    blPatternInit(@FHandle)
+  else
+    _BLCheck(blPatternInitAs(@FHandle, AImage.Handle, @AArea, Ord(AExtendMode), nil));
+end;
+
+constructor TBLPattern.Create(const AImage: IBLImage; const AArea: TBLRectI;
+  const AExtendMode: TBLExtendMode; const AMatrix: TBLMatrix2D);
+begin
+  inherited Create;
+  FImage := AImage;
+  if (AImage = nil) then
+    blPatternInit(@FHandle)
+  else
+    _BLCheck(blPatternInitAs(@FHandle, AImage.Handle, @AArea, Ord(AExtendMode), @AMatrix));
+end;
+
+constructor TBLPattern.Create(const AHandle: BLPatternCore;
+  const AIsReference: Boolean);
+begin
+  inherited Create;
+  FHandle := AHandle;
+  FIsReference := AIsReference;
+  FImage := TBLImage.Create(FHandle.impl.image, True);
+end;
+
+destructor TBLPattern.Destroy;
+begin
+  if (not FIsReference) then
+    blPatternDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLPattern.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLPattern) then
+    Result := blPatternEquals(@FHandle, @TBLPattern(Obj).FHandle)
+  else
+    Result := False;
+end;
+
+function TBLPattern.Equals(const AOther: IBLPattern): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := blPatternEquals(@FHandle, AOther.Handle)
+end;
+
+function TBLPattern.GetArea: TBLRectI;
+begin
+  Result.FHandle := FHandle.impl.area;
+end;
+
+function TBLPattern.GetExtendMode: TBLExtendMode;
+begin
+  Result := TBLExtendMode(FHandle.impl.extendMode);
+end;
+
+function TBLPattern.GetHandle: PBLPatternCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLPattern.GetHasMatrix: Boolean;
+begin
+  Result := (FHandle.impl.matrixType <> BL_MATRIX2D_TYPE_IDENTITY);
+end;
+
+function TBLPattern.GetImage: IBLImage;
+begin
+  Result := FImage;
+end;
+
+function TBLPattern.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLPattern.GetMatrix: TBLMatrix2D;
+begin
+  Result.FHandle := FHandle.impl.matrix;
+end;
+
+function TBLPattern.GetMatrixType: TBLMatrix2DType;
+begin
+  Result := TBLMatrix2DType(FHandle.impl.matrixType);
+end;
+
+procedure TBLPattern.Initialize(const AImage: IBLImage; const AArea: TBLRectI;
+  const AExtendMode: TBLExtendMode; const AMatrix: TBLMatrix2D);
+begin
+  FImage := AImage;
+  if (AImage <> nil) then
+    _BLCheck(blPatternCreate(@FHandle, AImage.Handle, @AArea, Ord(AExtendMode), @AMatrix));
+end;
+
+procedure TBLPattern.Initialize(const AImage: IBLImage;
+  const AExtendMode: TBLExtendMode);
+begin
+  FImage := AImage;
+  if (AImage <> nil) then
+    _BLCheck(blPatternCreate(@FHandle, AImage.Handle, nil, Ord(AExtendMode), nil));
+end;
+
+procedure TBLPattern.Initialize(const AImage: IBLImage;
+  const AExtendMode: TBLExtendMode; const AMatrix: TBLMatrix2D);
+begin
+  FImage := AImage;
+  if (AImage <> nil) then
+    _BLCheck(blPatternCreate(@FHandle, AImage.Handle, nil, Ord(AExtendMode), @AMatrix));
+end;
+
+procedure TBLPattern.Initialize(const AImage: IBLImage; const AArea: TBLRectI;
+  const AExtendMode: TBLExtendMode);
+begin
+  FImage := AImage;
+  if (AImage <> nil) then
+    _BLCheck(blPatternCreate(@FHandle, AImage.Handle, @AArea, Ord(AExtendMode), nil));
+end;
+
+procedure TBLPattern.PostRotate(const AAngle: Double);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE, @AAngle));
+end;
+
+procedure TBLPattern.PostRotate(const AAngle, AX, AY: Double);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AX;
+  Data[2] := AY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLPattern.PostRotate(const AAngle: Double; const AP: TBLPointI);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLPattern.PostRotate(const AAngle: Double; const AP: TBLPoint);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLPattern.PostScale(const AP: TBLPoint);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @AP));
+end;
+
+procedure TBLPattern.PostScale(const AP: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AP.FHandle.x;
+  Data[1] := AP.FHandle.y;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @Data));
+end;
+
+procedure TBLPattern.PostScale(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @Data));
+end;
+
+procedure TBLPattern.PostScale(const AXY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AXY;
+  Data[1] := AXY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @Data));
+end;
+
+procedure TBLPattern.PostSkew(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SKEW, @Data));
+end;
+
+procedure TBLPattern.PostSkew(const AP: TBLPoint);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SKEW, @AP));
+end;
+
+procedure TBLPattern.PostTransform(const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSFORM, @AMatrix));
+end;
+
+procedure TBLPattern.PostTranslate(const AP: TBLPoint);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSLATE, @AP));
+end;
+
+procedure TBLPattern.PostTranslate(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSLATE, @Data));
+end;
+
+procedure TBLPattern.PostTranslate(const AP: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AP.FHandle.x;
+  Data[1] := AP.FHandle.y;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSLATE, @Data));
+end;
+
+procedure TBLPattern.Reset;
+begin
+  _BLCheck(blPatternReset(@FHandle));
+end;
+
+procedure TBLPattern.ResetArea;
+var
+  Area: TBLRectI;
+begin
+  Area.Reset(0, 0, 0, 0);
+  _BLCheck(blPatternSetArea(@FHandle, @Area));
+end;
+
+procedure TBLPattern.ResetExtendMode;
+begin
+  _BLCheck(blPatternSetExtendMode(@FHandle, BL_EXTEND_MODE_REPEAT));
+end;
+
+procedure TBLPattern.ResetImage;
+begin
+  FImage := TBLImage.Create;
+  _BLCheck(blPatternSetImage(@FHandle, FImage.Handle, nil));
+end;
+
+procedure TBLPattern.ResetMatrix;
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_RESET, nil));
+end;
+
+procedure TBLPattern.Rotate(const AAngle: Double; const AP: TBLPoint);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLPattern.Rotate(const AAngle, AX, AY: Double);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AX;
+  Data[2] := AY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLPattern.Rotate(const AAngle: Double);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE, @AAngle));
+end;
+
+procedure TBLPattern.Rotate(const AAngle: Double; const AP: TBLPointI);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AP.FHandle.x;
+  Data[2] := AP.FHandle.y;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLPattern.Scale(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @Data));
+end;
+
+procedure TBLPattern.Scale(const AXY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AXY;
+  Data[1] := AXY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @Data));
+end;
+
+procedure TBLPattern.Scale(const AP: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AP.FHandle.x;
+  Data[1] := AP.FHandle.y;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @Data));
+end;
+
+procedure TBLPattern.Scale(const AP: TBLPoint);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @AP));
+end;
+
+procedure TBLPattern.SetArea(const AValue: TBLRectI);
+begin
+  _BLCheck(blPatternSetArea(@FHandle, @AValue));
+end;
+
+procedure TBLPattern.SetExtendMode(const AValue: TBLExtendMode);
+begin
+  _BLCheck(blPatternSetExtendMode(@FHandle, Ord(AValue)));
+end;
+
+procedure TBLPattern.SetImage(const AValue: IBLImage; const AArea: TBLRectI);
+begin
+  if (AValue <> nil) then
+    _BLCheck(blPatternSetImage(@FHandle, AValue.Handle, @AArea));
+end;
+
+procedure TBLPattern.SetImage(const AValue: IBLImage);
+begin
+  if (AValue <> nil) then
+    _BLCheck(blPatternSetImage(@FHandle, AValue.Handle, nil));
+end;
+
+procedure TBLPattern.SetMatrix(const AValue: TBLMatrix2D);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_ASSIGN, @AValue));
+end;
+
+procedure TBLPattern.Skew(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SKEW, @Data));
+end;
+
+procedure TBLPattern.Skew(const AP: TBLPoint);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_SKEW, @AP));
+end;
+
+procedure TBLPattern.Transform(const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSFORM, @AMatrix));
+end;
+
+procedure TBLPattern.Translate(const AP: TBLPoint);
+begin
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSLATE, @AP));
+end;
+
+procedure TBLPattern.Translate(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSLATE, @Data));
+end;
+
+procedure TBLPattern.Translate(const AP: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AP.FHandle.x;
+  Data[1] := AP.FHandle.y;
+  _BLCheck(blPatternApplyMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSLATE, @Data));
+end;
+
+{$ENDREGION 'Pattern'}
+
+{$REGION 'Font Defs'}
+
+{ TBLGlyphInfo }
+
+procedure TBLGlyphInfo.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+{ TBLGlyphPlacement }
+
+function TBLGlyphPlacement.GetAdvance: TBLPointI;
+begin
+  Result.FHandle := FHandle.advance;
+end;
+
+function TBLGlyphPlacement.GetPlacement: TBLPointI;
+begin
+  Result.FHandle := FHandle.placement;
+end;
+
+procedure TBLGlyphPlacement.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLGlyphPlacement.SetAdvance(const AValue: TBLPointI);
+begin
+  FHandle.advance := AValue.FHandle;
+end;
+
+procedure TBLGlyphPlacement.SetPlacement(const AValue: TBLPointI);
+begin
+  FHandle.placement := AValue.FHandle;
+end;
+
+{ TBLGlyphMappingState }
+
+function TBLGlyphMappingState.GetGlyphCount: Integer;
+begin
+  Result := FHandle.glyphCount;
+end;
+
+function TBLGlyphMappingState.GetUndefinedCount: Integer;
+begin
+  Result := FHandle.undefinedCount;
+end;
+
+function TBLGlyphMappingState.GetUndefinedFirst: Integer;
+begin
+  Result := FHandle.undefinedFirst;
+end;
+
+procedure TBLGlyphMappingState.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLGlyphMappingState.SetGlyphCount(const AValue: Integer);
+begin
+  FHandle.glyphCount := AValue;
+end;
+
+procedure TBLGlyphMappingState.SetUndefinedCount(const AValue: Integer);
+begin
+  FHandle.undefinedCount := AValue;
+end;
+
+procedure TBLGlyphMappingState.SetUndefinedFirst(const AValue: Integer);
+begin
+  FHandle.undefinedFirst := AValue;
+end;
+
+{ TBLGlyphOutlineSinkInfo }
+
+function TBLGlyphOutlineSinkInfo.GetContourCount: Integer;
+begin
+  Result := FHandle.contourCount;
+end;
+
+function TBLGlyphOutlineSinkInfo.GetGlyphIndex: Integer;
+begin
+  Result := FHandle.glyphIndex;
+end;
+
+procedure TBLGlyphOutlineSinkInfo.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLGlyphOutlineSinkInfo.SetContourCount(const AValue: Integer);
+begin
+  FHandle.contourCount := AValue;
+end;
+
+procedure TBLGlyphOutlineSinkInfo.SetGlyphIndex(const AValue: Integer);
+begin
+  FHandle.glyphIndex := AValue;
+end;
+
+{ TBLGlyphRun }
+
+function TBLGlyphRun.Entries<TPlacement>: TEnumerable<TPlacement>;
+begin
+  Result := TEnumerable<TPlacement>.Create(@FHandle);
+end;
+
+function TBLGlyphRun.GetFlags: TBLGlyphRunFlags;
+begin
+  Cardinal(Result) := FHandle.flags;
+end;
+
+function TBLGlyphRun.GetIsEmpty: Boolean;
+begin
+  Result := (FHandle.size = 0);
+end;
+
+function TBLGlyphRun.GetPlacementType: TBLGlyphPlacementType;
+begin
+  Result := TBLGlyphPlacementType(FHandle.placementType);
+end;
+
+function TBLGlyphRun.GetSize: Integer;
+begin
+  Result := FHandle.size;
+end;
+
+procedure TBLGlyphRun.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLGlyphRun.ResetGlyphIdData;
+begin
+  FHandle.glyphData := nil;
+  FHandle.glyphAdvance := 0;
+end;
+
+procedure TBLGlyphRun.ResetPlacementData;
+begin
+  FHandle.placementData := nil;
+  FHandle.placementAdvance := 0;
+end;
+
+procedure TBLGlyphRun.SetFlags(const AValue: TBLGlyphRunFlags);
+begin
+  FHandle.flags := Cardinal(AValue);
+end;
+
+procedure TBLGlyphRun.SetGlyphData(const AData: Pointer;
+  const AAdvance: Integer);
+begin
+  FHandle.glyphData := AData;
+  FHandle.glyphAdvance := AAdvance;
+end;
+
+procedure TBLGlyphRun.SetGlyphData(const AData: PCardinal);
+begin
+  FHandle.glyphData := AData;
+  FHandle.glyphAdvance := SizeOf(Cardinal);
+end;
+
+procedure TBLGlyphRun.SetGlyphData(const AData: PWord);
+begin
+  FHandle.glyphData := AData;
+  FHandle.glyphAdvance := SizeOf(Word);
+end;
+
+procedure TBLGlyphRun.SetPlacementData(const AData: Pointer;
+  const AAdvance: Integer);
+begin
+  FHandle.placementData := AData;
+  FHandle.placementAdvance := AAdvance;
+end;
+
+procedure TBLGlyphRun.SetPlacementType(const AValue: TBLGlyphPlacementType);
+begin
+  FHandle.placementType := Ord(AValue);
+end;
+
+procedure TBLGlyphRun.SetSize(const AValue: Integer);
+begin
+  FHandle.size := AValue;
+end;
+
+{ TBLGlyphRun.TEnumerable<T> }
+
+constructor TBLGlyphRun.TEnumerable<T>.Create(const AHandle: _PBLGlyphRun);
+begin
+  FHandle := AHandle;
+end;
+
+function TBLGlyphRun.TEnumerable<T>.GetEnumerator: TEnumerator<T>;
+begin
+  Result := TEnumerator<T>.Create(FHandle);
+end;
+
+{ TBLGlyphRun.TEnumerator<T> }
+
+constructor TBLGlyphRun.TEnumerator<T>.Create(const AHandle: _PBLGlyphRun);
+begin
+  FGlyphData := AHandle.glyphData;
+  FPlacementData := AHandle.placementData;
+  FGlyphAdvance := AHandle.glyphAdvance;
+  FPlacementAdvance := AHandle.placementAdvance;
+  FHigh := AHandle.size;
+  Dec(FHigh);
+  FIndex := -1;
+  Dec(FGlyphData, FGlyphAdvance);
+  Dec(FPlacementData, FPlacementAdvance);
+end;
+
+function TBLGlyphRun.TEnumerator<T>.GetCurrent: TBLGlyphRunEntry<T>;
+begin
+  Result.GlyphId := PWord(FGlyphData)^;
+  Result.Placement := P(FPlacementData)^;
+end;
+
+function TBLGlyphRun.TEnumerator<T>.MoveNext: Boolean;
+begin
+  Result := (FIndex < FHigh);
+  if Result then
+  begin
+    Inc(FIndex);
+    Inc(FGlyphData, FGlyphAdvance);
+    Inc(FPlacementData, FPlacementAdvance);
+  end;
+end;
+
+{ TBLFontFaceInfo }
+
+function TBLFontFaceInfo.GetDiagFlags: TBLFontFaceDiagFlags;
+begin
+  Word(Result) := FHandle.diagFlags;
+end;
+
+function TBLFontFaceInfo.GetFaceFlags: TBLFontFaceFlags;
+begin
+  Cardinal(Result) := FHandle.faceFlags;
+end;
+
+function TBLFontFaceInfo.GetFaceType: TBLFontFaceType;
+begin
+  Result := TBLFontFaceType(FHandle.faceType);
+end;
+
+function TBLFontFaceInfo.GetGlyphCount: Integer;
+begin
+  Result := FHandle.glyphCount;
+end;
+
+function TBLFontFaceInfo.GetOutlineType: TBLFontOutlineType;
+begin
+  Result := TBLFontOutlineType(FHandle.outlineType);
+end;
+
+procedure TBLFontFaceInfo.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLFontFaceInfo.SetDiagFlags(const AValue: TBLFontFaceDiagFlags);
+begin
+  FHandle.diagFlags := Word(AValue);
+end;
+
+procedure TBLFontFaceInfo.SetFaceFlags(const AValue: TBLFontFaceFlags);
+begin
+  FHandle.faceFlags := Cardinal(AValue);
+end;
+
+procedure TBLFontFaceInfo.SetFaceType(const AValue: TBLFontFaceType);
+begin
+  FHandle.faceType := Ord(AValue);
+end;
+
+procedure TBLFontFaceInfo.SetGlyphCount(const AValue: Integer);
+begin
+  FHandle.glyphCount := AValue;
+end;
+
+procedure TBLFontFaceInfo.SetOutlineType(const AValue: TBLFontOutlineType);
+begin
+  FHandle.outlineType := Ord(AValue);
+end;
+
+{ TBLFontQueryProperties }
+
+function TBLFontQueryProperties.GetStretch: TBLFontStretch;
+begin
+  Result := TBLFontStretch(FHandle.stretch);
+end;
+
+function TBLFontQueryProperties.GetStyle: TBLFontStyle;
+begin
+  Result := TBLFontStyle(FHandle.style);
+end;
+
+function TBLFontQueryProperties.GetWeight: TBLFontWeight;
+begin
+  Result := TBLFontWeight(FHandle.weight);
+end;
+
+procedure TBLFontQueryProperties.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLFontQueryProperties.SetStretch(const AValue: TBLFontStretch);
+begin
+  FHandle.stretch := Ord(AValue);
+end;
+
+procedure TBLFontQueryProperties.SetStyle(const AValue: TBLFontStyle);
+begin
+  FHandle.style := Ord(AValue);
+end;
+
+procedure TBLFontQueryProperties.SetWeight(const AValue: TBLFontWeight);
+begin
+  FHandle.weight := Ord(AValue);
+end;
+
+{ TBLFontTable }
+
+function TBLFontTable.GetSize: Integer;
+begin
+  Result := FHandle.size;
+end;
+
+procedure TBLFontTable.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLFontTable.Reset(const AData: Pointer; const ASize: Integer);
+begin
+  FHandle.data := AData;
+  FHandle.size := ASize;
+end;
+
+procedure TBLFontTable.SetSize(const AValue: Integer);
+begin
+  FHandle.size := AValue;
+end;
+
+{ TBLFontFeature }
+
+procedure TBLFontFeature.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+{ TBLFontVariation }
+
+procedure TBLFontVariation.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+{ TBLFontUnicodeCoverage }
+
+procedure TBLFontUnicodeCoverage.ClearBit(
+  const AIndex: TBLFontUnicodeCoverageIndex);
+var
+  I: Integer;
+begin
+  I := Ord(AIndex);
+  FHandle.data[I shr 5] := FHandle.data[I shr 5] and not (1 shl (I and 31));
+end;
+
+class operator TBLFontUnicodeCoverage.Equal(const ALeft,
+  ARight: TBLFontUnicodeCoverage): Boolean;
+begin
+  Result := (ALeft.FHandle.data[0] = ARight.FHandle.data[0])
+        and (ALeft.FHandle.data[1] = ARight.FHandle.data[1])
+        and (ALeft.FHandle.data[2] = ARight.FHandle.data[2])
+        and (ALeft.FHandle.data[3] = ARight.FHandle.data[3]);
+end;
+
+function TBLFontUnicodeCoverage.GetBit(
+  const AIndex: TBLFontUnicodeCoverageIndex): Boolean;
+var
+  I: Integer;
+begin
+  I := Ord(AIndex);
+  Result := (((FHandle.data[I shr 5] shr (I and 31)) and 1) <> 0);
+end;
+
+function TBLFontUnicodeCoverage.GetIsEmpty: Boolean;
+begin
+  Result := (FHandle.data[0] = 0) and (FHandle.data[1] = 0)
+        and (FHandle.data[2] = 0) and (FHandle.data[3] = 0);
+end;
+
+class operator TBLFontUnicodeCoverage.NotEqual(const ALeft,
+  ARight: TBLFontUnicodeCoverage): Boolean;
+begin
+  Result := not (ALeft = ARight);
+end;
+
+procedure TBLFontUnicodeCoverage.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLFontUnicodeCoverage.SetBit(
+  const AIndex: TBLFontUnicodeCoverageIndex; const AValue: Boolean);
+begin
+  if (AValue) then
+    SetBit(AIndex)
+  else
+    ClearBit(AIndex);
+end;
+
+procedure TBLFontUnicodeCoverage.SetBit(
+  const AIndex: TBLFontUnicodeCoverageIndex);
+var
+  I: Integer;
+begin
+  I := Ord(AIndex);
+  FHandle.data[I shr 5] := FHandle.data[I shr 5] or (1 shl (I and 31));
+end;
+
+{ TBLFontPanose }
+
+function TBLFontPanose.GetIsEmpty: Boolean;
+begin
+  Result := (Data[0] = 0) and (Data[1] = 0)
+        and (Data[2] = 0) and (Data[3] = 0)
+        and (Data[4] = 0) and (Data[5] = 0)
+        and (Data[6] = 0) and (Data[7] = 0)
+        and (Data[8] = 0) and (Data[9] = 0);
+end;
+
+procedure TBLFontPanose.Reset;
+begin
+  FillChar(Self, SizeOf(Self), 0);
+end;
+
+{ TBLFontMatrix }
+
+function BLFontMatrix(const AM00, AM01, AM10, AM11: Double): TBLFontMatrix; inline;
+begin
+  Result.Reset(AM00, AM01, AM10, AM11);
+end;
+
+function TBLFontMatrix.GetElement(const AIndex: Integer): Double;
+begin
+  Assert(Cardinal(AIndex) < 4);
+  Result := FHandle.m[AIndex];
+end;
+
+procedure TBLFontMatrix.Reset;
+begin
+  FHandle.m00 := 1;
+  FHandle.m01 := 0;
+  FHandle.m10 := 0;
+  FHandle.m11 := 1;
+end;
+
+procedure TBLFontMatrix.Reset(const AM00, AM01, AM10, AM11: Double);
+begin
+  FHandle.m00 := AM00;
+  FHandle.m01 := AM01;
+  FHandle.m10 := AM10;
+  FHandle.m11 := AM11;
+end;
+
+procedure TBLFontMatrix.SetElement(const AIndex: Integer; const AValue: Double);
+begin
+  Assert(Cardinal(AIndex) < 4);
+  FHandle.m[AIndex] := AValue;
+end;
+
+{ TBLFontMetrics }
+
+procedure TBLFontMetrics.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+{ TBLFontDesignMetrics }
+
+function TBLFontDesignMetrics.GetGlyphBoundingBox: TBLBoxI;
+begin
+  Result.FHandle := FHandle.glyphBoundingBox;
+end;
+
+procedure TBLFontDesignMetrics.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLFontDesignMetrics.SetGlyphBoundingBox(const AValue: TBLBoxI);
+begin
+  FHandle.glyphBoundingBox := AValue.FHandle;
+end;
+
+{ TBLTextMetrics }
+
+function TBLTextMetrics.GetAdvance: TBLPoint;
+begin
+  Result.FHandle := FHandle.advance;
+end;
+
+function TBLTextMetrics.GetBoundingBox: TBLBox;
+begin
+  Result.FHandle := FHandle.boundingBox;
+end;
+
+function TBLTextMetrics.GetLeadingBearing: TBLPoint;
+begin
+  Result.FHandle := FHandle.leadingBearing;
+end;
+
+function TBLTextMetrics.GetTrailingBearing: TBLPoint;
+begin
+  Result.FHandle := FHandle.trailingBearing;
+end;
+
+procedure TBLTextMetrics.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLTextMetrics.SetAdvance(const AValue: TBLPoint);
+begin
+  FHandle.advance := AValue.FHandle;
+end;
+
+procedure TBLTextMetrics.SetBoundingBox(const AValue: TBLBox);
+begin
+  FHandle.boundingBox := AValue.FHandle;
+end;
+
+procedure TBLTextMetrics.SetLeadingBearing(const AValue: TBLPoint);
+begin
+  FHandle.leadingBearing := AValue.FHandle;
+end;
+
+procedure TBLTextMetrics.SetTrailingBearing(const AValue: TBLPoint);
+begin
+  FHandle.trailingBearing := AValue.FHandle;
+end;
+
+{$ENDREGION 'Font Defs'}
+
+{$REGION 'Glyph Buffer'}
+
+{ TBLGlyphBuffer }
+
+procedure TBLGlyphBuffer.Clear;
+begin
+  _BLCheck(blGlyphBufferClear(@FHandle));
+end;
+
+constructor TBLGlyphBuffer.Create;
+begin
+  inherited;
+  blGlyphBufferInit(@FHandle);
+end;
+
+destructor TBLGlyphBuffer.Destroy;
+begin
+  blGlyphBufferDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLGlyphBuffer.GetContent: PCardinal;
+begin
+  Result := PCardinal(FHandle.impl.data.content);
+end;
+
+function TBLGlyphBuffer.GetFlags: TBLGlyphRunFlags;
+begin
+  Cardinal(Result) := FHandle.impl.data.flags;
+end;
+
+function TBLGlyphBuffer.GetGlyphRun: PBLGlyphRun;
+begin
+  Result := @FHandle.impl.data.glyphRun;
+end;
+
+function TBLGlyphBuffer.GetHandle: PBLGlyphBufferCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLGlyphBuffer.GetHasGlyphs: Boolean;
+begin
+  Result := ((FHandle.impl.data.flags and BL_GLYPH_RUN_FLAG_UCS4_CONTENT) = 0);
+end;
+
+function TBLGlyphBuffer.GetHasInvalidChars: Boolean;
+begin
+  Result := ((FHandle.impl.data.flags and BL_GLYPH_RUN_FLAG_INVALID_TEXT) <> 0);
+end;
+
+function TBLGlyphBuffer.GetHasInvalidFontData: Boolean;
+begin
+  Result := ((FHandle.impl.data.flags and BL_GLYPH_RUN_FLAG_INVALID_FONT_DATA) <> 0);
+end;
+
+function TBLGlyphBuffer.GetHasText: Boolean;
+begin
+  Result := ((FHandle.impl.data.flags and BL_GLYPH_RUN_FLAG_UCS4_CONTENT) <> 0);
+end;
+
+function TBLGlyphBuffer.GetHasUndefinedChars: Boolean;
+begin
+  Result := ((FHandle.impl.data.flags and BL_GLYPH_RUN_FLAG_UNDEFINED_GLYPHS) <> 0);
+end;
+
+function TBLGlyphBuffer.GetInfoData: PBLGlyphInfo;
+begin
+  Result := PBLGlyphInfo(FHandle.impl.infoData);
+end;
+
+function TBLGlyphBuffer.GetIsEmpty: Boolean;
+begin
+  Result := (FHandle.impl.data.glyphRun.size = 0);
+end;
+
+function TBLGlyphBuffer.GetPlacementData: PBLGlyphPlacement;
+begin
+  Result := PBLGlyphPlacement(FHandle.impl.data.placementData);
+end;
+
+function TBLGlyphBuffer.GetSize: Integer;
+begin
+  Result := FHandle.impl.data.size;
+end;
+
+function TBLGlyphBuffer.HasFlag(const AFlag: TBLGlyphRunFlag): Boolean;
+begin
+  Result := ((FHandle.impl.data.flags and Ord(AFlag)) <> 0);
+end;
+
+procedure TBLGlyphBuffer.Reset;
+begin
+  _BLCheck(blGlyphBufferReset(@FHandle));
+end;
+
+procedure TBLGlyphBuffer.SetGlyphs(const AGlyphData: Pointer; const ASize,
+  AGlyphIdSize, AGlyphAdvance: Integer);
+begin
+  _BLCheck(blGlyphBufferSetGlyphsFromStruct(@FHandle, AGlyphData, ASize,
+    AGlyphIdSize, AGlyphAdvance));
+end;
+
+procedure TBLGlyphBuffer.SetGlyphs(const AGlyphData: PCardinal;
+  const ALength: Integer);
+begin
+  _BLCheck(blGlyphBufferSetGlyphs(@FHandle, Pointer(AGlyphData), ALength));
+end;
+
+procedure TBLGlyphBuffer.SetGlyphs(const AGlyphData: TArray<Cardinal>);
+begin
+  _BLCheck(blGlyphBufferSetGlyphs(@FHandle, Pointer(AGlyphData), Length(AGlyphData)));
+end;
+
+procedure TBLGlyphBuffer.SetText(const AText: String);
+begin
+  _BLCheck(blGlyphBufferSetText(@FHandle, PChar(AText), Length(AText), BL_TEXT_ENCODING_UTF16));
+end;
+
+procedure TBLGlyphBuffer.SetText(const AText: Pointer; const ALength: Integer;
+  const AEncoding: TBLTextEncoding);
+begin
+  _BLCheck(blGlyphBufferSetText(@FHandle, AText, ALength, Ord(AEncoding)));
+end;
+
+procedure TBLGlyphBuffer.SetText(const AText: UCS4String);
+begin
+  _BLCheck(blGlyphBufferSetText(@FHandle, Pointer(AText), Length(AText) - 1, BL_TEXT_ENCODING_UTF32));
+end;
+
+procedure TBLGlyphBuffer.SetText(const AText: UTF8String);
+begin
+  _BLCheck(blGlyphBufferSetText(@FHandle, PUTF8Char(AText), Length(AText), BL_TEXT_ENCODING_UTF8));
+end;
+
+{$ENDREGION 'Glyph Buffer'}
+
+{$REGION 'Font'}
+
+{ TBLFontData }
+
+constructor TBLFontData.Create;
+begin
+  inherited;
+  blFontDataInit(@FHandle);
+end;
+
+constructor TBLFontData.Create(const AHandle: BLFontDataCore;
+  const AIsReference: Boolean);
+begin
+  inherited Create;
+  FHandle := AHandle;
+  FIsReference := AIsReference;
+end;
+
+destructor TBLFontData.Destroy;
+begin
+  if (not FIsReference) then
+    blFontDataDestroy(@FHandle);
+  inherited;
+end;
+
+class procedure TBLFontData.DoDestroy(impl, destroyData: Pointer);
+var
+  Data: PDestroyData absolute destroyData;
+begin
+  if (Data <> nil) then
+  begin
+    Data.Event(Data.FontData);
+    FreeMem(Data);
+  end;
+end;
+
+function TBLFontData.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLFontData) then
+    Result := blFontDataEquals(@FHandle, @TBLFontData(Obj).FHandle)
+  else
+    Result := False;
+end;
+
+function TBLFontData.Equals(const AOther: IBLFontData): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := blFontDataEquals(@FHandle, AOther.Handle)
+end;
+
+function TBLFontData.GetFaceCount: Integer;
+begin
+  Result := FHandle.impl.faceCount;
+end;
+
+function TBLFontData.GetFaceType: TBLFontFaceType;
+begin
+  Result := TBLFontFaceType(FHandle.impl.faceType);
+end;
+
+function TBLFontData.GetFlags: TBLFontDataFlags;
+begin
+  Byte(Result) := FHandle.impl.flags;
+end;
+
+function TBLFontData.GetHandle: PBLFontDataCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLFontData.GetIsCollection: Boolean;
+begin
+  Result := ((FHandle.impl.flags and BL_FONT_DATA_FLAG_COLLECTION) <> 0);
+end;
+
+function TBLFontData.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLFontData.GetTags(const AFaceIndex: Integer): TArray<TBLTag>;
+var
+  Tags: IBLArray;
+begin
+  Tags := TBLUtils.CreateBLArray<TBLTag>;
+  _BLCheck(blFontDataListTags(@FHandle, AFaceIndex, Tags.Handle));
+  Result := TBLUtils.BLArrayToArray<TBLTag>(Tags);
+end;
+
+procedure TBLFontData.InitializeFromData(const AData: TBytes);
+var
+  Data: IBLArray;
+begin
+  if (AData <> nil) then
+  begin
+    Data := TBLUtils.ArrayToBLArray<Byte>(AData);
+    _BLCheck(blFontDataCreateFromDataArray(@FHandle, Data.Handle));
+  end;
+end;
+
+procedure TBLFontData.InitializeFromData(const AData: Pointer;
+  const ASize: Integer; const AOnDestroy: TBLFontDataDestroyEvent);
+var
+  DestroyFunc: BLDestroyImplFunc;
+  DestroyData: PDestroyData;
+begin
+  if Assigned(AOnDestroy) then
+  begin
+    DestroyFunc := DoDestroy;
+    GetMem(DestroyData, SizeOf(TDestroyData));
+    DestroyData.FontData := Self;
+    DestroyData.Event := AOnDestroy;
+  end
+  else
+  begin
+    DestroyFunc := nil;
+    DestroyData := nil;
+  end;
+  _BLCheck(blFontDataCreateFromData(@FHandle, AData, ASize, DestroyFunc, DestroyData));
+end;
+
+procedure TBLFontData.InitializeFromFile(const AFilename: String;
+  const AReadFlags: TBLFileReadFlags);
+begin
+  _BLCheck(blFontDataCreateFromFile(@FHandle, MarshaledAString(UTF8String(AFilename)),
+    Byte(AReadFlags)));
+end;
+
+function TBLFontData.QueryTable(const AFaceIndex: Integer; const ATag: TBLTag;
+  out ATable: TBLFontTable): Integer;
+begin
+  Result := blFontDataQueryTables(@FHandle, AFaceIndex, @ATable.FHandle, @ATag, 1);
+end;
+
+function TBLFontData.QueryTables(const AFaceIndex: Integer;
+  const ATags: TArray<TBLTag>; out ATables: TArray<TBLFontTable>): Integer;
+begin
+  SetLength(ATables, Length(ATags));
+  Result := blFontDataQueryTables(@FHandle, AFaceIndex, Pointer(ATables),
+    Pointer(ATags), Length(ATags));
+end;
+
+procedure TBLFontData.Reset;
+begin
+  _BLCheck(blFontDataReset(@FHandle));
+end;
+
+{ TBLFontFace }
+
+constructor TBLFontFace.Create;
+begin
+  inherited;
+  blFontFaceInit(@FHandle);
+end;
+
+constructor TBLFontFace.Create(const AHandle: BLFontFaceCore;
+  const AIsReference: Boolean);
+begin
+  inherited Create;
+  FHandle := AHandle;
+  FIsReference := AIsReference;
+end;
+
+destructor TBLFontFace.Destroy;
+begin
+  if (not FIsReference) then
+    blFontFaceDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLFontFace.Equals(const AOther: IBLFontFace): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := blFontFaceEquals(@FHandle, AOther.Handle)
+end;
+
+function TBLFontFace.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLFontFace) then
+    Result := blFontFaceEquals(@FHandle, @TBLFontFace(Obj).FHandle)
+  else
+    Result := False;
+end;
+
+function TBLFontFace.GetData: IBLFontData;
+begin
+  if (FData = nil) then
+    FData := TBLFontData.Create(FHandle.impl.data, True);
+
+  Result := FData;
+end;
+
+function TBLFontFace.GetDesignMetrics: TBLFontDesignMetrics;
+begin
+  Result.FHandle := FHandle.impl.designMetrics;
+end;
+
+function TBLFontFace.GetDiagFlags: TBLFontFaceDiagFlags;
+begin
+  Word(Result) := FHandle.impl.faceInfo.diagFlags;
+end;
+
+function TBLFontFace.GetFaceFlags: TBLFontFaceFlags;
+begin
+  Cardinal(Result) := FHandle.impl.faceInfo.faceFlags;
+end;
+
+function TBLFontFace.GetFaceIndex: Integer;
+begin
+  Result := FHandle.impl.faceInfo.faceIndex;
+end;
+
+function TBLFontFace.GetFaceInfo: TBLFontFaceInfo;
+begin
+  Result.FHandle := FHandle.impl.faceInfo;
+end;
+
+function TBLFontFace.GetFaceType: TBLFontFaceType;
+begin
+  Result := TBLFontFaceType(FHandle.impl.faceInfo.faceType);
+end;
+
+function TBLFontFace.GetFamilyName: String;
+var
+  S: UTF8String;
+begin
+  SetString(S, FHandle.impl.familyName.impl.data, FHandle.impl.familyName.impl.size);
+  Result := String(S);
+end;
+
+function TBLFontFace.GetFullName: String;
+var
+  S: UTF8String;
+begin
+  SetString(S, FHandle.impl.fullName.impl.data, FHandle.impl.fullName.impl.size);
+  Result := String(S);
+end;
+
+function TBLFontFace.GetHandle: PBLFontFaceCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLFontFace.GetHasBaselineYAt0: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_BASELINE_Y_EQUALS_0) <> 0);
+end;
+
+function TBLFontFace.GetHasCharToGlyphMapping: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_CHAR_TO_GLYPH_MAPPING) <> 0);
+end;
+
+function TBLFontFace.GetHasHorizontalKerning: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_HORIZONTAL_KERNING) <> 0);
+end;
+
+function TBLFontFace.GetHasHorizontalMetrics: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_HORIZONTAL_METRICS) <> 0);
+end;
+
+function TBLFontFace.GetHasLSBPointXAt0: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_LSB_POINT_X_EQUALS_0) <> 0);
+end;
+
+function TBLFontFace.GetHasOpenTypeFeatures: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_OPENTYPE_FEATURES) <> 0);
+end;
+
+function TBLFontFace.GetHasOpenTypeVariations: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_OPENTYPE_VARIATIONS) <> 0);
+end;
+
+function TBLFontFace.GetHasPanoseData: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_PANOSE_DATA) <> 0);
+end;
+
+function TBLFontFace.GetHasTypographicMetrics: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_TYPOGRAPHIC_METRICS) <> 0);
+end;
+
+function TBLFontFace.GetHasTypographicNames: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_TYPOGRAPHIC_NAMES) <> 0);
+end;
+
+function TBLFontFace.GetHasUnicodeCoverage: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_UNICODE_COVERAGE) <> 0);
+end;
+
+function TBLFontFace.GetHasVariationSequences: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_VARIATION_SEQUENCES) <> 0);
+end;
+
+function TBLFontFace.GetHasVerticalKerning: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_VERTICAL_KERNING) <> 0);
+end;
+
+function TBLFontFace.GetHasVerticalMetrics: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_VERTICAL_METRICS) <> 0);
+end;
+
+function TBLFontFace.GetIsLastResortFont: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_LAST_RESORT_FONT) <> 0);
+end;
+
+function TBLFontFace.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLFontFace.GetIsSymbolFont: Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and BL_FONT_FACE_FLAG_SYMBOL_FONT) <> 0);
+end;
+
+function TBLFontFace.GetOutlineType: TBLFontOutlineType;
+begin
+  Result := TBLFontOutlineType(FHandle.impl.faceInfo.outlineType);
+end;
+
+function TBLFontFace.GetPanose: TBLFontPanose;
+begin
+  Result := TBLFontPanose(FHandle.impl.panose);
+end;
+
+function TBLFontFace.GetPostScriptName: String;
+var
+  S: UTF8String;
+begin
+  SetString(S, FHandle.impl.postScriptName.impl.data, FHandle.impl.postScriptName.impl.size);
+  Result := String(S);
+end;
+
+function TBLFontFace.GetStretch: TBLFontStretch;
+begin
+  Result := TBLFontStretch(FHandle.impl.stretch);
+end;
+
+function TBLFontFace.GetStyle: TBLFontStyle;
+begin
+  Result := TBLFontStyle(FHandle.impl.style);
+end;
+
+function TBLFontFace.GetSubfamilyName: String;
+var
+  S: UTF8String;
+begin
+  SetString(S, FHandle.impl.subfamilyName.impl.data, FHandle.impl.subfamilyName.impl.size);
+  Result := String(S);
+end;
+
+function TBLFontFace.GetUnicodeCoverage: TBLFontUnicodeCoverage;
+begin
+  Result.FHandle := FHandle.impl.unicodeCoverage;
+end;
+
+function TBLFontFace.GetUniqueId: TBLUniqueId;
+begin
+  Result := FHandle.impl.uniqueId;
+end;
+
+function TBLFontFace.GetUnitsPerEm: Integer;
+begin
+  Result := FHandle.impl.designMetrics.unitsPerEm;
+end;
+
+function TBLFontFace.GetWeight: TBLFontWeight;
+begin
+  Result := TBLFontWeight(FHandle.impl.weight);
+end;
+
+function TBLFontFace.HasFaceFlag(const AFlag: TBLFontFaceFlag): Boolean;
+begin
+  Result := ((FHandle.impl.faceInfo.faceFlags and Ord(AFlag)) <> 0);
+end;
+
+procedure TBLFontFace.InitializeFromData(const AFontData: IBLFontData;
+  const AFaceIndex: Integer);
+begin
+  FData := AFontData;
+  if (AFontData <> nil) then
+    _BLCheck(blFontFaceCreateFromData(@FHandle, AFontData.Handle, AFaceIndex));
+end;
+
+procedure TBLFontFace.InitializeFromFile(const AFilename: String;
+  const AReadFlags: TBLFileReadFlags);
+begin
+  _BLCheck(blFontFaceCreateFromFile(@FHandle, MarshaledAString(UTF8String(AFilename)),
+    Byte(AReadFlags)));
+end;
+
+procedure TBLFontFace.Reset;
+begin
+  _BLCheck(blFontFaceReset(@FHandle));
+end;
+
+{ TBLFont }
+
+procedure TBLFont.ApplyGPos(const AGlyphBuffer: IBLGlyphBuffer;
+  const AIndex: Integer; const ALookups: TBLBitWord);
+begin
+  if (AGlyphBuffer <> nil) then
+    _BLCheck(blFontApplyGPos(@FHandle, AGlyphBuffer.Handle, AIndex, ALookups));
+end;
+
+procedure TBLFont.ApplyGSub(const AGlyphBuffer: IBLGlyphBuffer;
+  const AIndex: Integer; const ALookups: TBLBitWord);
+begin
+  if (AGlyphBuffer <> nil) then
+    _BLCheck(blFontApplyGSub(@FHandle, AGlyphBuffer.Handle, AIndex, ALookups));
+end;
+
+procedure TBLFont.ApplyKerning(const AGlyphBuffer: IBLGlyphBuffer);
+begin
+  if (AGlyphBuffer <> nil) then
+    _BLCheck(blFontApplyKerning(@FHandle, AGlyphBuffer.Handle));
+end;
+
+constructor TBLFont.Create;
+begin
+  inherited;
+  blFontInit(@FHandle);
+end;
+
+destructor TBLFont.Destroy;
+begin
+  blFontDestroy(@FHandle);
+  inherited;
+end;
+
+class function TBLFont.DoSink(path: PBLPathCore; info,
+  closure: Pointer): Cardinal;
+var
+  Font: TBLFont;
+begin
+  Result := 0;
+  if Assigned(closure) then
+  begin
+    Font := TBLFont(Closure);
+    if Assigned(Font.FSink) then
+      Result := Ord(Font.FSink(Font.FSinkPath, info));
+  end;
+end;
+
+function TBLFont.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLFont) then
+    Result := blFontEquals(@FHandle, @TBLFont(Obj).FHandle)
+  else
+    Result := False;
+end;
+
+function TBLFont.Equals(const AOther: IBLFont): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := blFontEquals(@FHandle, AOther.Handle)
+end;
+
+function TBLFont.GetDesignMetrics: TBLFontDesignMetrics;
+begin
+  Result.FHandle := FHandle.impl.face.impl.designMetrics;
+end;
+
+function TBLFont.GetFace: IBLFontFace;
+begin
+  Result := FFace;
+end;
+
+function TBLFont.GetFaceFlags: TBLFontFaceFlags;
+begin
+  Result := TBLFontFaceFlags(FHandle.impl.face.impl.faceInfo.faceFlags);
+end;
+
+function TBLFont.GetFaceType: TBLFontFaceType;
+begin
+  Result := TBLFontFaceType(FHandle.impl.face.impl.faceInfo.faceType);
+end;
+
+function TBLFont.GetFeatures: TArray<TBLFontFeature>;
+begin
+  Result := TBLUtils.BLArrayToArray<TBLFontFeature>(FHandle.impl.features);
+end;
+
+function TBLFont.GetGlyphAdvances(const AGlyphData: PCardinal;
+  const AGlyphAdvance, ACount: Integer): TArray<TBLGlyphPlacement>;
+begin
+  SetLength(Result, ACount);
+  _BLCheck(blFontGetGlyphAdvances(@FHandle, Pointer(AGlyphData), AGlyphAdvance,
+    Pointer(Result), ACount));
+end;
+
+function TBLFont.GetGlyphBounds(const AGlyphData: PCardinal;
+  const AGlyphAdvance, ACount: Integer): TArray<TBLBoxI>;
+begin
+  SetLength(Result, ACount);
+  _BLCheck(blFontGetGlyphBounds(@FHandle, Pointer(AGlyphData), AGlyphAdvance,
+    Pointer(Result), ACount));
+end;
+
+function TBLFont.GetGlyphOutlines(const AGlyphId: Cardinal;
+  const AUserMatrix: TBLMatrix2D; const ASink: TBLPathSinkEvent): IBLPath;
+var
+  Sink: BLPathSinkFunc;
+  Closure: Pointer;
+begin
+  Result := TBLPath.Create;
+  if Assigned(ASink) then
+  begin
+    FSink := ASink;
+    FSinkPath := Result;
+    Sink := DoSink;
+    Closure := Self;
+  end
+  else
+  begin
+    Sink := nil;
+    Closure := nil;
+  end;
+  _BLCheck(blFontGetGlyphOutlines(@FHandle, AGlyphId, @AUserMatrix,
+    Result.Handle, Sink, Closure));
+end;
+
+function TBLFont.GetGlyphOutlines(const AGlyphId: Cardinal;
+  const ASink: TBLPathSinkEvent): IBLPath;
+var
+  Sink: BLPathSinkFunc;
+  Closure: Pointer;
+begin
+  Result := TBLPath.Create;
+  if Assigned(ASink) then
+  begin
+    FSink := ASink;
+    FSinkPath := Result;
+    Sink := DoSink;
+    Closure := Self;
+  end
+  else
+  begin
+    Sink := nil;
+    Closure := nil;
+  end;
+  _BLCheck(blFontGetGlyphOutlines(@FHandle, AGlyphId, nil,
+    Result.Handle, Sink, Closure));
+end;
+
+function TBLFont.GetGlyphRunOutlines(const AGlyphRun: TBLGlyphRun;
+  const AUserMatrix: TBLMatrix2D; const ASink: TBLPathSinkEvent): IBLPath;
+var
+  Sink: BLPathSinkFunc;
+  Closure: Pointer;
+begin
+  Result := TBLPath.Create;
+  if Assigned(ASink) then
+  begin
+    FSink := ASink;
+    FSinkPath := Result;
+    Sink := DoSink;
+    Closure := Self;
+  end
+  else
+  begin
+    Sink := nil;
+    Closure := nil;
+  end;
+  _BLCheck(blFontGetGlyphRunOutlines(@FHandle, @AGlyphRun, @AUserMatrix,
+    Result.Handle, Sink, Closure));
+end;
+
+function TBLFont.GetGlyphRunOutlines(const AGlyphRun: TBLGlyphRun;
+  const ASink: TBLPathSinkEvent): IBLPath;
+var
+  Sink: BLPathSinkFunc;
+  Closure: Pointer;
+begin
+  Result := TBLPath.Create;
+  if Assigned(ASink) then
+  begin
+    FSink := ASink;
+    FSinkPath := Result;
+    Sink := DoSink;
+    Closure := Self;
+  end
+  else
+  begin
+    Sink := nil;
+    Closure := nil;
+  end;
+  _BLCheck(blFontGetGlyphRunOutlines(@FHandle, @AGlyphRun, nil,
+    Result.Handle, Sink, Closure));
+end;
+
+function TBLFont.GetHandle: PBLFontCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLFont.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLFont.GetMatrix: TBLFontMatrix;
+begin
+  Result.FHandle := FHandle.impl.matrix;
+end;
+
+function TBLFont.GetMetrics: TBLFontMetrics;
+begin
+  Result.FHandle := FHandle.impl.metrics;
+end;
+
+function TBLFont.GetMetricsPtr: PBLFontMetrics;
+begin
+  Result := @FHandle.impl.metrics;
+end;
+
+function TBLFont.GetSize: Single;
+begin
+  Result := FHandle.impl.metrics.size;
+end;
+
+function TBLFont.GetStretch: TBLFontStretch;
+begin
+  Result := TBLFontStretch(FHandle.impl.stretch);
+end;
+
+function TBLFont.GetStyle: TBLFontStyle;
+begin
+  Result := TBLFontStyle(FHandle.impl.style);
+end;
+
+function TBLFont.GetTextMetrics(
+  const AGlyphBuffer: IBLGlyphBuffer): TBLTextMetrics;
+begin
+  if (AGlyphBuffer <> nil) then
+    _BLCheck(blFontGetTextMetrics(@FHandle, AGlyphBuffer.Handle, @Result.FHandle));
+end;
+
+function TBLFont.GetUnitsPerEm: Integer;
+begin
+  Result := FHandle.impl.face.impl.designMetrics.unitsPerEm;
+end;
+
+function TBLFont.GetVariations: TArray<TBLFontVariation>;
+begin
+  Result := TBLUtils.BLArrayToArray<TBLFontVariation>(FHandle.impl.variations);
+end;
+
+function TBLFont.GetWeight: TBLFontWeight;
+begin
+  Result := TBLFontWeight(FHandle.impl.weight);
+end;
+
+procedure TBLFont.InitializeFromFace(const AFace: IBLFontFace;
+  const ASize: Single);
+begin
+  if (AFace <> nil) then
+    _BLCheck(blFontCreateFromFace(@FHandle, AFace.Handle, ASize));
+end;
+
+procedure TBLFont.MapTextToGlyphs(const AGlyphBuffer: IBLGlyphBuffer);
+begin
+  if (AGlyphBuffer <> nil) then
+    _BLCheck(blFontMapTextToGlyphs(@FHandle, AGlyphBuffer.Handle, nil));
+end;
+
+procedure TBLFont.MapTextToGlyphs(const AGlyphBuffer: IBLGlyphBuffer;
+  out AState: TBLGlyphMappingState);
+begin
+  if (AGlyphBuffer <> nil) then
+    _BLCheck(blFontMapTextToGlyphs(@FHandle, AGlyphBuffer.Handle, @AState.FHandle));
+end;
+
+procedure TBLFont.PositionGlyphs(const AGlyphBuffer: IBLGlyphBuffer;
+  const APositioningFlags: Cardinal);
+begin
+  if (AGlyphBuffer <> nil) then
+    _BLCheck(blFontPositionGlyphs(@FHandle, AGlyphBuffer.Handle, APositioningFlags));
+end;
+
+procedure TBLFont.Reset;
+begin
+  _BLCheck(blFontReset(@FHandle));
+end;
+
+procedure TBLFont.Shape(const AGlyphBuffer: IBLGlyphBuffer);
+begin
+  if (AGlyphBuffer <> nil) then
+    _BLCheck(blFontShape(@FHandle, AGlyphBuffer.Handle));
+end;
+
+{$ENDREGION 'Font'}
+
+{$REGION 'Font Manager'}
+
+{ TBLFontManager }
+
+procedure TBLFontManager.AddFace(const AFace: IBLFontFace);
+begin
+  if (AFace <> nil) then
+    _BLCheck(blFontManagerAddFace(@FHandle, AFace.Handle));
+end;
+
+constructor TBLFontManager.Create;
+begin
+  inherited;
+  _BLCheck(blFontManagerInit(@FHandle));
+end;
+
+destructor TBLFontManager.Destroy;
+begin
+  blFontManagerDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLFontManager.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLFontManager) then
+    Result := blFontManagerEquals(@FHandle, @TBLFontManager(Obj).FHandle)
+  else
+    Result := False;
+end;
+
+function TBLFontManager.Equals(const AOther: IBLFontManager): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := blFontManagerEquals(@FHandle, AOther.Handle);
+end;
+
+function TBLFontManager.GetFaceCount: Integer;
+begin
+  Result := blFontManagerGetFaceCount(@FHandle);
+end;
+
+function TBLFontManager.GetFamilyCount: Integer;
+begin
+  Result := blFontManagerGetFamilyCount(@FHandle);
+end;
+
+function TBLFontManager.GetHandle: PBLFontManagerCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLFontManager.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLFontManager.HasFace(const AFace: IBLFontFace): Boolean;
+begin
+  if (AFace <> nil) then
+    Result := blFontManagerHasFace(@FHandle, AFace.Handle)
+  else
+    Result := False;
+end;
+
+procedure TBLFontManager.Initialize;
+begin
+  blFontManagerCreate(@FHandle);
+end;
+
+function TBLFontManager.QueryFace(const AName: String): IBLFontFace;
+var
+  Name: UTF8String;
+  Face: BLFontFaceCore;
+begin
+  Name := UTF8String(AName);
+  if (blFontManagerQueryFace(@FHandle, MarshaledAString(Name), Length(Name),
+    nil, @Face) = BL_SUCCESS)
+  then
+    Result := TBLFontFace.Create(Face, True)
+  else
+    Result := nil;
+end;
+
+function TBLFontManager.QueryFace(const AName: String;
+  const AProperties: TBLFontQueryProperties): IBLFontFace;
+var
+  Name: UTF8String;
+  Face: BLFontFaceCore;
+begin
+  Name := UTF8String(AName);
+  if (blFontManagerQueryFace(@FHandle, MarshaledAString(Name), Length(Name),
+    @AProperties.FHandle, @Face) = BL_SUCCESS)
+  then
+    Result := TBLFontFace.Create(Face, True)
+  else
+    Result := nil;
+end;
+
+function TBLFontManager.QueryFacesByFamilyName(
+  const AName: String): TArray<IBLFontFace>;
+var
+  Name: UTF8String;
+  FaceArray: IBLArray;
+  FaceHandles: TArray<BLFontFaceCore>;
+  I: Integer;
+begin
+  Name := UTF8String(AName);
+  FaceArray := TBLUtils.CreateBLArray<BLFontFaceCore>;
+  if (blFontManagerQueryFacesByFamilyName(@FHandle, MarshaledAString(Name),
+    Length(Name), FaceArray.Handle) = BL_SUCCESS) then
+  begin
+    FaceHandles := TBLUtils.BLArrayToArray<BLFontFaceCore>(FaceArray);
+    SetLength(Result, Length(FaceHandles));
+    for I := 0 to Length(Result) - 1 do
+      Result[I] := TBLFontFace.Create(FaceHandles[I], True);
+  end
+  else
+    Result := nil;
+end;
+
+procedure TBLFontManager.Reset;
+begin
+  _BLCheck(blFontManagerReset(@FHandle));
+end;
+
+{$ENDREGION 'Font Manager'}
+
+{$REGION 'Pixel Converter'}
+
+{ TBLPixelConverterOptions }
+
+function TBLPixelConverterOptions.GetGap: Integer;
+begin
+  Result := FHandle.gap;
+end;
+
+function TBLPixelConverterOptions.GetOrigin: TBLPointI;
+begin
+  Result.FHandle := FHandle.origin;
+end;
+
+procedure TBLPixelConverterOptions.SetGap(const AValue: Integer);
+begin
+  FHandle.gap := AValue;
+end;
+
+procedure TBLPixelConverterOptions.SetOrigin(const AValue: TBLPointI);
+begin
+  FHandle.origin := AValue.FHandle;
+end;
+
+{ TBLPixelConverter }
+
+procedure TBLPixelConverter.Assign(const AOther: IBLPixelConverter);
+begin
+  if Assigned(AOther) then
+    _BLCheck(blPixelConverterAssign(@FHandle, AOther.Handle));
+end;
+
+procedure TBLPixelConverter.ConvertRect(const ASrcData: Pointer;
+  const ASrcStride: Integer; const ADstData: Pointer; const ADstStride, AWidth,
+  AHeight: Integer; const AOptions: TBLPixelConverterOptions);
+begin
+  _BLCheck(blPixelConverterConvert(@FHandle, ADstData, ADstStride, ASrcData,
+    ASrcStride, AWidth, AHeight, @AOptions.FHandle));
+end;
+
+procedure TBLPixelConverter.ConvertRect(const ASrcData: Pointer;
+  const ASrcStride: Integer; const ADstData: Pointer; const ADstStride, AWidth,
+  AHeight: Integer);
+begin
+  _BLCheck(blPixelConverterConvert(@FHandle, ADstData, ADstStride, ASrcData,
+    ASrcStride, AWidth, AHeight, nil));
+end;
+
+procedure TBLPixelConverter.ConvertSpan(const ASrcData, ADstData: Pointer;
+  const AWidth: Integer);
+begin
+  _BLCheck(blPixelConverterConvert(@FHandle, ADstData, 0, ASrcData, 0,
+    AWidth, 1, nil));
+end;
+
+procedure TBLPixelConverter.ConvertSpan(const ASrcData, ADstData: Pointer;
+  const AWidth: Integer; const AOptions: TBLPixelConverterOptions);
+begin
+  _BLCheck(blPixelConverterConvert(@FHandle, ADstData, 0, ASrcData, 0,
+    AWidth, 1, @AOptions.FHandle));
+end;
+
+constructor TBLPixelConverter.Create;
+begin
+  inherited;
+  blPixelConverterInit(@FHandle);
+end;
+
+class function TBLPixelConverter.CreatePlatformConverter: IBLPixelConverter;
+var
+  SrcFormat, DstFormat: TBLFormatInfo;
+begin
+  Result := TBLPixelConverter.Create;
+  SrcFormat := TBLFormat.PRGB32.Info;
+  DstFormat := SrcFormat;
+
+  {$IFNDEF MSWINDOWS}
+  DstFormat.RedShift := SrcFormat.BlueShift;
+  DstFormat.BlueShift := SrcFormat.RedShift;
+  {$ENDIF}
+
+  Result.Initialize(SrcFormat, DstFormat, [TBLPixelConverterCreateFlag.NoMultiStep]);
+end;
+
+destructor TBLPixelConverter.Destroy;
+begin
+  blPixelConverterDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLPixelConverter.GetHandle: PBLPixelConverterCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLPixelConverter.GetIsInitialized: Boolean;
+begin
+  Result := (FHandle.internalFlags <> 0);
+end;
+
+procedure TBLPixelConverter.Initialize(const ASrcInfo, ADstInfo: TBLFormatInfo;
+  const ACreateFlags: TBLPixelConverterCreateFlags);
+begin
+  _BLCheck(blPixelConverterCreate(@FHandle, @ADstInfo.FHandle,
+    @ASrcInfo.FHandle, Byte(ACreateFlags)));
+end;
+
+procedure TBLPixelConverter.Reset;
+begin
+  _BLCheck(blPixelConverterReset(@FHandle));
+end;
+
+{$ENDREGION 'Pixel Converter'}
+
+{$REGION 'Context'}
+
+{ TBLContextCreateInfo }
+
+function TBLContextCreateInfo.GetFlags: TBLContextCreateFlags;
+begin
+  Cardinal(Result) := FHandle.flags;
+end;
+
+procedure TBLContextCreateInfo.Reset;
+begin
+  FillChar(FHandle, SizeOf(FHandle), 0);
+end;
+
+procedure TBLContextCreateInfo.SetFlags(const AValue: TBLContextCreateFlags);
+begin
+  FHandle.flags := Cardinal(AValue);
+end;
+
+{ TBLContextCookie }
+
+class operator TBLContextCookie.Equal(const ALeft,
+  ARight: TBLContextCookie): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBLContextCookie.Equals(const AOther: TBLContextCookie): Boolean;
+begin
+  Result := (FHandle.data[0] = AOther.FHandle.data[0])
+        and (FHandle.data[1] = AOther.FHandle.data[1]);
+end;
+
+function TBLContextCookie.GetIsEmpty: Boolean;
+begin
+  Result := (FHandle.data[0] = 0) and (FHandle.data[1] = 0);
+end;
+
+class operator TBLContextCookie.NotEqual(const ALeft,
+  ARight: TBLContextCookie): Boolean;
+begin
+  Result := not ALeft.Equals(ARight);
+end;
+
+procedure TBLContextCookie.Reset(const AData0, AData1: UInt64);
+begin
+ FHandle.data[0] := AData0;
+ FHandle.data[1] := AData1;
+end;
+
+procedure TBLContextCookie.Reset(const AOther: TBLContextCookie);
+begin
+  Self := AOther;
+end;
+
+procedure TBLContextCookie.Reset;
+begin
+  Reset(0, 0);
+end;
+
+{ TBLContextHints }
+
+function TBLContextHints.GetGradientQuality: TBLGradientQuality;
+begin
+  Result := TBLGradientQuality(FHandle.gradientQuality);
+end;
+
+function TBLContextHints.GetPatternQuality: TBLPatternQuality;
+begin
+  Result := TBLPatternQuality(FHandle.patternQuality);
+end;
+
+function TBLContextHints.GetRenderingQuality: TBLRenderingQuality;
+begin
+  Result := TBLRenderingQuality(FHandle.renderingQuality);
+end;
+
+procedure TBLContextHints.SetGradientQuality(const AValue: TBLGradientQuality);
+begin
+  FHandle.gradientQuality := Ord(AValue);
+end;
+
+procedure TBLContextHints.SetPatternQuality(const AValue: TBLPatternQuality);
+begin
+  FHandle.patternQuality := Ord(AValue);
+end;
+
+procedure TBLContextHints.SetRenderingQuality(const AValue: TBLRenderingQuality);
+begin
+  FHandle.renderingQuality := Ord(AValue);
+end;
+
+{ TBLContextState }
+
+function TBLContextState.GetApproximationOptions: TBLApproximationOptions;
+begin
+  Result.FHandle := FHandle.approximationOptions;
+end;
+
+function TBLContextState.GetCompOp: TBLCompOp;
+begin
+  Result := TBLCompOp(FHandle.compOp);
+end;
+
+function TBLContextState.GetFillAlpha: Double;
+begin
+  Result := FHandle.styleAlpha[BL_CONTEXT_OP_TYPE_FILL];
+end;
+
+function TBLContextState.GetFillRule: TBLFillRule;
+begin
+  Result := TBLFillRule(FHandle.fillRule);
+end;
+
+function TBLContextState.GetFillStyle: TBLStyleType;
+begin
+  Result := TBLStyleType(FHandle.styleType[BL_CONTEXT_OP_TYPE_FILL]);
+end;
+
+function TBLContextState.GetHints: TBLContextHints;
+begin
+  Result.FHandle := FHandle.hints;
+end;
+
+function TBLContextState.GetMetaMatrix: TBLMatrix2D;
+begin
+  Result.FHandle := FHandle.metaMatrix;
+end;
+
+function TBLContextState.GetSavedStateCount: Integer;
+begin
+  Result := FHandle.savedStateCount;
+end;
+
+function TBLContextState.GetStrokeOptions: TBLStrokeOptions;
+begin
+  Result.FHandle := FHandle.strokeOptions;
+end;
+
+function TBLContextState.GetStrokeStyle: TBLStyleType;
+begin
+  Result := TBLStyleType(FHandle.styleType[BL_CONTEXT_OP_TYPE_STROKE]);
+end;
+
+function TBLContextState.GetTargetImage: IBLImage;
+begin
+  if (FHandle.targetImage = nil) then
+    Result := nil
+  else
+    Result := TBLImage.Create(FHandle.targetImage^, True);
+end;
+
+function TBLContextState.GetTargetSize: TBLSize;
+begin
+  Result := TBLSize(FHandle.targetSize);
+end;
+
+function TBLContextState.GetStrokeAlpha: Double;
+begin
+  Result := FHandle.styleAlpha[BL_CONTEXT_OP_TYPE_STROKE];
+end;
+
+function TBLContextState.GetUserMatrix: TBLMatrix2D;
+begin
+  Result.FHandle := FHandle.userMatrix;
+end;
+
+{ TBLContext }
+
+procedure TBLContext.BlitImage(const ADst: TBLPointI; const ASrc: IBLImage);
+begin
+  _BLCheck(blContextBlitImageI(@FHandle, @ADst, ASrc.Handle, nil));
+end;
+
+procedure TBLContext.BlitImage(const ADst: TBLRect; const ASrc: IBLImage);
+begin
+  _BLCheck(blContextBlitScaledImageD(@FHandle, @ADst, ASrc.Handle, nil));
+end;
+
+procedure TBLContext.BlitImage(const ADst: TBLPointI; const ASrc: IBLImage;
+  const ASrcArea: TBLRectI);
+begin
+  _BLCheck(blContextBlitImageI(@FHandle, @ADst, ASrc.Handle, @ASrcArea));
+end;
+
+procedure TBLContext.BlitImage(const ADst: TBLPoint; const ASrc: IBLImage;
+  const ASrcArea: TBLRectI);
+begin
+  _BLCheck(blContextBlitImageD(@FHandle, @ADst, ASrc.Handle, @ASrcArea));
+end;
+
+procedure TBLContext.BlitImage(const ADst: TBLPoint; const ASrc: IBLImage);
+begin
+  _BLCheck(blContextBlitImageD(@FHandle, @ADst, ASrc.Handle, nil));
+end;
+
+procedure TBLContext.BlitImage(const ADst: TBLRectI; const ASrc: IBLImage);
+begin
+  _BLCheck(blContextBlitScaledImageI(@FHandle, @ADst, ASrc.Handle, nil));
+end;
+
+procedure TBLContext.BlitImage(const ADst: TBLRect; const ASrc: IBLImage;
+  const ASrcArea: TBLRectI);
+begin
+  _BLCheck(blContextBlitScaledImageD(@FHandle, @ADst, ASrc.Handle, @ASrcArea));
+end;
+
+procedure TBLContext.AfterConstruction;
+begin
+  inherited;
+  { Blend2D requires that floating-point calculations do not raise exceptions.}
+  SetExceptionMask(exAllArithmeticExceptions);
+end;
+
+procedure TBLContext.BlitImage(const ADst: TBLRectI; const ASrc: IBLImage;
+  const ASrcArea: TBLRectI);
+begin
+  _BLCheck(blContextBlitScaledImageI(@FHandle, @ADst, ASrc.Handle, @ASrcArea));
+end;
+
+procedure TBLContext.ClearAll;
+begin
+  _BLCheck(blContextClearAll(@FHandle));
+end;
+
+procedure TBLContext.ClearRect(const ARect: TBLRectI);
+begin
+  _BLCheck(blContextClearRectI(@FHandle, @ARect));
+end;
+
+procedure TBLContext.ClearRect(const ARect: TBLRect);
+begin
+  _BLCheck(blContextClearRectD(@FHandle, @ARect));
+end;
+
+procedure TBLContext.ClearRect(const AX, AY, AW, AH: Double);
+var
+  R: TBLRect;
+begin
+  R.Reset(AX, AY, AW, AH);
+  _BLCheck(blContextClearRectD(@FHandle, @R));
+end;
+
+procedure TBLContext.ClipToRect(const AX, AY, AW, AH: Double);
+var
+  R: TBLRect;
+begin
+  R.Reset(AX, AY, AW, AH);
+  _BLCheck(blContextClipToRectD(@FHandle, @R));
+end;
+
+procedure TBLContext.ClipToRect(const ARect: TBLRect);
+begin
+  _BLCheck(blContextClipToRectD(@FHandle, @ARect));
+end;
+
+procedure TBLContext.ClipToRect(const ARect: TBLRectI);
+begin
+  _BLCheck(blContextClipToRectI(@FHandle, @ARect));
+end;
+
+constructor TBLContext.Create;
+begin
+  inherited Create;
+  blContextInit(@FHandle);
+end;
+
+constructor TBLContext.Create(const ATarget: IBLImage);
+begin
+  inherited Create;
+  if (ATarget = nil) then
+    blContextInit(@FHandle)
+  else
+    _BLCheck(blContextInitAs(@FHandle, ATarget.Handle, nil));
+end;
+
+constructor TBLContext.Create(const ATarget: IBLImage;
+  const ACreateInfo: TBLContextCreateInfo);
+begin
+  inherited Create;
+  if (ATarget = nil) then
+    blContextInit(@FHandle)
+  else
+    _BLCheck(blContextInitAs(@FHandle, ATarget.Handle, @ACreateInfo.FHandle));
+end;
+
+destructor TBLContext.Destroy;
+begin
+  blContextDestroy(@FHandle);
+  inherited;
+end;
+
+function TBLContext.Equals(Obj: TObject): Boolean;
+begin
+  if (Obj = nil) then
+    Result := (Self = nil)
+  else if (Obj = Self) then
+    Result := True
+  else if (Obj is TBLContext) then
+    Result := (FHandle.impl = TBLContext(Obj).FHandle.impl)
+  else
+    Result := False;
+end;
+
+function TBLContext.Equals(const AOther: IBLContext): Boolean;
+begin
+  if (AOther = nil) then
+    Result := (Self = nil)
+  else
+    Result := (FHandle.impl = AOther.Handle.impl)
+end;
+
+procedure TBLContext.FillAll;
+begin
+  _BLCheck(blContextFillAll(@FHandle));
+end;
+
+procedure TBLContext.FillBox(const AX0, AY0, AX1, AY1: Double);
+var
+  Box: TBLBox;
+begin
+  Box.Reset(AX0, AY0, AX1, AY1);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_BOXD, @Box));
+end;
+
+procedure TBLContext.FillBox(const ABox: TBLBox);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_BOXD, @ABox));
+end;
+
+procedure TBLContext.FillBox(const ABox: TBLBoxI);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_BOXI, @ABox));
+end;
+
+procedure TBLContext.FillBoxArray(const ABoxes: PBLBox; const ACount: Integer);
+var
+  View: TBLArrayView<TBLBox>;
+begin
+  View.Reset(ABoxes, ACount);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @View));
+end;
+
+procedure TBLContext.FillBoxArray(const ABoxes: TArray<TBLBoxI>);
+var
+  View: TBLArrayView<TBLBoxI>;
+begin
+  View.Reset(Pointer(ABoxes), Length(ABoxes));
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @View));
+end;
+
+procedure TBLContext.FillBoxArray(const ABoxes: TBLArrayView<TBLBoxI>);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @ABoxes));
+end;
+
+procedure TBLContext.FillBoxArray(const ABoxes: PBLBoxI; const ACount: Integer);
+var
+  View: TBLArrayView<TBLBoxI>;
+begin
+  View.Reset(ABoxes, ACount);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @View));
+end;
+
+procedure TBLContext.FillBoxArray(const ABoxes: TBLArrayView<TBLBox>);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @ABoxes));
+end;
+
+procedure TBLContext.FillBoxArray(const ABoxes: TArray<TBLBox>);
+var
+  View: TBLArrayView<TBLBox>;
+begin
+  View.Reset(Pointer(ABoxes), Length(ABoxes));
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @View));
+end;
+
+procedure TBLContext.FillChord(const ACX, ACY, ARX, ARY, AStart,
+  ASweep: Double);
+var
+  Chord: TBLArc;
+begin
+  Chord.Reset(ACX, ACY, ARX, ARY, AStart, ASweep);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_CHORD, @Chord));
+end;
+
+procedure TBLContext.FillChord(const ACX, ACY, AR, AStart, ASweep: Double);
+var
+  Chord: TBLArc;
+begin
+  Chord.Reset(ACX, ACY, AR, AStart, ASweep);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_CHORD, @Chord));
+end;
+
+procedure TBLContext.FillChord(const AChord: TBLArc);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_CHORD, @AChord));
+end;
+
+procedure TBLContext.FillCircle(const ACX, ACY, AR: Double);
+var
+  Circle: TBLCircle;
+begin
+  Circle.Reset(ACX, ACY, AR);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_CIRCLE, @Circle));
+end;
+
+procedure TBLContext.FillCircle(const ACircle: TBLCircle);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_CIRCLE, @ACircle));
+end;
+
+procedure TBLContext.FillEllipse(const AEllipse: TBLEllipse);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ELLIPSE, @AEllipse));
+end;
+
+procedure TBLContext.FillEllipse(const ACX, ACY, ARX, ARY: Double);
+var
+  Ellipse: TBLEllipse;
+begin
+  Ellipse.Reset(ACX, ACY, ARX, ARY);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ELLIPSE, @Ellipse));
+end;
+
+procedure TBLContext.FillGlyphRun(const ADst: TBLPoint; const AFont: IBLFont;
+  const AGlyphRun: TBLGlyphRun);
+var
+  Font: PBLFontCore;
+begin
+  if (AFont = nil) then
+    Font := nil
+  else
+    Font := AFont.Handle;
+
+  _BLCheck(blContextFillGlyphRunD(@FHandle, @ADst, Font, @AGlyphRun));
+end;
+
+procedure TBLContext.FillGlyphRun(const ADst: TBLPointI; const AFont: IBLFont;
+  const AGlyphRun: TBLGlyphRun);
+var
+  Font: PBLFontCore;
+begin
+  if (AFont = nil) then
+    Font := nil
+  else
+    Font := AFont.Handle;
+
+  _BLCheck(blContextFillGlyphRunI(@FHandle, @ADst, Font, @AGlyphRun));
+end;
+
+procedure TBLContext.FillGlyphRun(const ADst: TBLPoint; const AFont: IBLFont;
+  const AGlyphRun: PBLGlyphRun);
+var
+  Font: PBLFontCore;
+begin
+  if (AGlyphRun <> nil) then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextFillGlyphRunD(@FHandle, @ADst, Font, Pointer(AGlyphRun)));
+  end;
+end;
+
+procedure TBLContext.FillGlyphRun(const ADst: TBLPointI; const AFont: IBLFont;
+  const AGlyphRun: PBLGlyphRun);
+var
+  Font: PBLFontCore;
+begin
+  if (AGlyphRun <> nil) then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextFillGlyphRunI(@FHandle, @ADst, Font, Pointer(AGlyphRun)));
+  end;
+end;
+
+procedure TBLContext.FillPath(const APath: IBLPath);
+begin
+  if (APath <> nil) then
+    _BLCheck(blContextFillPathD(@FHandle, APath.Handle));
+end;
+
+procedure TBLContext.FillPie(const ACX, ACY, AR, AStart, ASweep: Double);
+var
+  Pie: TBLArc;
+begin
+  Pie.Reset(ACX, ACY, AR, AStart, ASweep);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_PIE, @Pie));
+end;
+
+procedure TBLContext.FillPie(const ACX, ACY, ARX, ARY, AStart, ASweep: Double);
+var
+  Pie: TBLArc;
+begin
+  Pie.Reset(ACX, ACY, ARX, ARY, AStart, ASweep);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_PIE, @Pie));
+end;
+
+procedure TBLContext.FillPie(const APie: TBLArc);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_PIE, @APie));
+end;
+
+procedure TBLContext.FillPolygon(const APoly: TBLArrayView<TBLPoint>);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @APoly));
+end;
+
+procedure TBLContext.FillPolygon(const APoly: TArray<TBLPointI>);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(Pointer(APoly), Length(APoly));
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @View));
+end;
+
+procedure TBLContext.FillPolygon(const APoly: TBLArrayView<TBLPointI>);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @APoly));
+end;
+
+procedure TBLContext.FillPolygon(const APoly: PBLPointI; const ACount: Integer);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(APoly, ACount);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @View));
+end;
+
+procedure TBLContext.FillPolygon(const APoly: TArray<TBLPoint>);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(Pointer(APoly), Length(APoly));
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @View));
+end;
+
+procedure TBLContext.FillPolygon(const APoly: PBLPoint; const ACount: Integer);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(APoly, ACount);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @View));
+end;
+
+procedure TBLContext.FillRect(const AX, AY, AW, AH: Double);
+var
+  R: TBLRect;
+begin
+  R.Reset(AX, AY, AW, AH);
+  _BLCheck(blContextFillRectD(@FHandle, @R));
+end;
+
+procedure TBLContext.FillRect(const ARect: TBLRect);
+begin
+  _BLCheck(blContextFillRectD(@FHandle, @ARect));
+end;
+
+procedure TBLContext.FillRect(const ARect: TBLRectI);
+begin
+  _BLCheck(blContextFillRectI(@FHandle, @ARect));
+end;
+
+procedure TBLContext.FillRectArray(const ARects: PBLRect;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLRect>;
+begin
+  View.Reset(ARects, ACount);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @View));
+end;
+
+procedure TBLContext.FillRectArray(const ARects: TArray<TBLRectI>);
+var
+  View: TBLArrayView<TBLRectI>;
+begin
+  View.Reset(Pointer(ARects), Length(ARects));
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @View));
+end;
+
+procedure TBLContext.FillRectArray(const ARects: TBLArrayView<TBLRect>);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @ARects));
+end;
+
+procedure TBLContext.FillRectArray(const ARects: TArray<TBLRect>);
+var
+  View: TBLArrayView<TBLRect>;
+begin
+  View.Reset(Pointer(ARects), Length(ARects));
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @View));
+end;
+
+procedure TBLContext.FillRectArray(const ARects: TBLArrayView<TBLRectI>);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @ARects));
+end;
+
+procedure TBLContext.FillRectArray(const ARects: PBLRectI;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLRectI>;
+begin
+  View.Reset(ARects, ACount);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @View));
+end;
+
+procedure TBLContext.FillRegion(const ARegion: IBLRegion);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_REGION, ARegion.Handle));
+end;
+
+procedure TBLContext.FillRoundRect(const ARect: TBLRect; const AR: Double);
+var
+  RoundRect: TBLRoundRect;
+begin
+  RoundRect.Reset(ARect, AR);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @RoundRect));
+end;
+
+procedure TBLContext.FillRoundRect(const ARoundRect: TBLRoundRect);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @ARoundRect));
+end;
+
+procedure TBLContext.FillRoundRect(const AX, AY, AW, AH, AR: Double);
+var
+  RoundRect: TBLRoundRect;
+begin
+  RoundRect.Reset(AX, AY, AW, AH, AR);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @RoundRect));
+end;
+
+procedure TBLContext.FillRoundRect(const ARect: TBLRect; const ARX,
+  ARY: Double);
+var
+  RoundRect: TBLRoundRect;
+begin
+  RoundRect.Reset(ARect, ARX, ARY);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @RoundRect));
+end;
+
+procedure TBLContext.FillRoundRect(const AX, AY, AW, AH, ARX, ARY: Double);
+var
+  RoundRect: TBLRoundRect;
+begin
+  RoundRect.Reset(AX, AY, AW, AH, ARX, ARY);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @RoundRect));
+end;
+
+procedure TBLContext.FillText(const ADst: TBLPointI; const AFont: IBLFont;
+  const AText: UTF8String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> '') then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextFillTextI(@FHandle, @ADst, Font, Pointer(AText), Length(AText), BL_TEXT_ENCODING_UTF8));
+  end;
+end;
+
+procedure TBLContext.FillText(const ADst: TBLPoint; const AFont: IBLFont;
+  const AText: String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> '') then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextFillTextD(@FHandle, @ADst, Font, Pointer(AText), Length(AText), BL_TEXT_ENCODING_UTF16));
+  end;
+end;
+
+procedure TBLContext.FillText(const ADst: TBLPointI; const AFont: IBLFont;
+  const AText: String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> '') then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextFillTextI(@FHandle, @ADst, Font, Pointer(AText), Length(AText), BL_TEXT_ENCODING_UTF16));
+  end;
+end;
+
+procedure TBLContext.FillText(const ADst: TBLPoint; const AFont: IBLFont;
+  const AText: UCS4String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> nil) then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextFillTextD(@FHandle, @ADst, Font, Pointer(AText), Length(AText) - 1, BL_TEXT_ENCODING_UTF32));
+  end;
+end;
+
+procedure TBLContext.FillText(const ADst: TBLPointI; const AFont: IBLFont;
+  const AText: UCS4String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> nil) then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextFillTextI(@FHandle, @ADst, Font, Pointer(AText), Length(AText) - 1, BL_TEXT_ENCODING_UTF32));
+  end;
+end;
+
+procedure TBLContext.FillText(const ADst: TBLPoint; const AFont: IBLFont;
+  const AText: UTF8String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> '') then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextFillTextD(@FHandle, @ADst, Font, Pointer(AText), Length(AText), BL_TEXT_ENCODING_UTF8));
+  end;
+end;
+
+procedure TBLContext.FillTriangle(const AX0, AY0, AX1, AY1, AX2, AY2: Double);
+var
+  Triangle: TBLTriangle;
+begin
+  Triangle.Reset(AX0, AY0, AX1, AY1, AX2, AY2);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_TRIANGLE, @Triangle));
+end;
+
+procedure TBLContext.FillTriangle(const ATriangle: TBLTriangle);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_TRIANGLE, @ATriangle));
+end;
+
+procedure TBLContext.Finish;
+begin
+  _BLCheck(blContextEnd(@FHandle));
+end;
+
+procedure TBLContext.Flush(const AFlags: TBLContextFlushFlags);
+begin
+  _BLCheck(blContextFlush(@FHandle, Cardinal(AFlags)));
+end;
+
+function TBLContext.GetApproximationOptions: TBLApproximationOptions;
+begin
+  Result.FHandle := FHandle.impl.state.approximationOptions;
+end;
+
+function TBLContext.GetCompOp: TBLCompOp;
+begin
+  Result := TBLCompOp(FHandle.impl.state.compOp);
+end;
+
+function TBLContext.GetContextType: TBLContextType;
+begin
+  Result := TBLContextType(FHandle.impl.contextType);
+end;
+
+function TBLContext.GetFillAlpha: Double;
+begin
+  Result := FHandle.impl.state.styleAlpha[BL_CONTEXT_OP_TYPE_FILL];
+end;
+
+function TBLContext.GetFillColor: TBLRgba32;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  Result.Reset(TBLRgba(Style.rgba));
+end;
+
+function TBLContext.GetFillColor64: TBLRgba64;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  Result.Reset(TBLRgba(Style.rgba));
+end;
+
+function TBLContext.GetFillColorF: TBLRgba;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  Result := TBLRgba(Style.rgba);
+end;
+
+function TBLContext.GetFillGradient: IBLGradient;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  Result := TBLGradient.Create(Style.gradient, True);
+end;
+
+function TBLContext.GetFillPattern: IBLPattern;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  Result := TBLPattern.Create(Style.pattern, True);
+end;
+
+function TBLContext.GetFillRule: TBLFillRule;
+begin
+  Result := TBLFillRule(FHandle.impl.state.fillRule);
+end;
+
+procedure TBLContext.GetFillStyle(out ARgba: TBLRgba32);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  ARgba.Reset(TBLRgba(Style.rgba));
+end;
+
+procedure TBLContext.GetFillStyle(out ARgba: TBLRgba64);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  ARgba.Reset(TBLRgba(Style.rgba));
+end;
+
+procedure TBLContext.GetFillStyle(out AGradient: IBLGradient);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  AGradient := TBLGradient.Create(Style.gradient, True);
+end;
+
+procedure TBLContext.GetFillStyle(out ARgba: TBLRgba);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  ARgba := TBLRgba(Style.rgba);
+end;
+
+procedure TBLContext.GetFillStyle(out APattern: IBLPattern);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetFillStyle(@FHandle, @Style));
+  APattern := TBLPattern.Create(Style.pattern, True);
+end;
+
+function TBLContext.GetFillStyle: TBLStyleType;
+begin
+  Result := TBLStyleType(FHandle.impl.state.styleType[BL_CONTEXT_OP_TYPE_FILL]);
+end;
+
+function TBLContext.GetFlattenMode: TBLFlattenMode;
+begin
+  Result := TBLFlattenMode(FHandle.impl.state.approximationOptions.flattenMode);
+end;
+
+function TBLContext.GetFlattenTolerance: Double;
+begin
+  Result := FHandle.impl.state.approximationOptions.flattenTolerance;
+end;
+
+function TBLContext.GetGlobalAlpha: Double;
+begin
+  Result := FHandle.impl.state.globalAlpha;
+end;
+
+function TBLContext.GetGradientQuality: TBLGradientQuality;
+begin
+  Result := TBLGradientQuality(FHandle.impl.state.hints.gradientQuality);
+end;
+
+function TBLContext.GetHandle: PBLContextCore;
+begin
+  Result := @FHandle;
+end;
+
+function TBLContext.GetHints: TBLContextHints;
+begin
+  Result.FHandle := FHandle.impl.state.hints;
+end;
+
+function TBLContext.GetIsNone: Boolean;
+begin
+  Result := ((FHandle.impl.implTraits and BL_IMPL_TRAIT_NULL) <> 0);
+end;
+
+function TBLContext.GetMetaMatrix: TBLMatrix2D;
+begin
+  Result.FHandle := FHandle.impl.state.metaMatrix;
+end;
+
+function TBLContext.GetPatternQuality: TBLPatternQuality;
+begin
+  Result := TBLPatternQuality(FHandle.impl.state.hints.patternQuality);
+end;
+
+function TBLContext.GetRenderingQuality: TBLRenderingQuality;
+begin
+  Result := TBLRenderingQuality(FHandle.impl.state.hints.renderingQuality);
+end;
+
+function TBLContext.GetSavedStateCount: Integer;
+begin
+  Result := FHandle.impl.state.savedStateCount;
+end;
+
+function TBLContext.GetStrokeAlpha: Double;
+begin
+  Result := FHandle.impl.state.styleAlpha[BL_CONTEXT_OP_TYPE_STROKE];
+end;
+
+function TBLContext.GetStrokeColor: TBLRgba32;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  Result.Reset(TBLRgba(Style.rgba));
+end;
+
+function TBLContext.GetStrokeColor64: TBLRgba64;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  Result.Reset(TBLRgba(Style.rgba));
+end;
+
+function TBLContext.GetStrokeColorF: TBLRgba;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  Result := TBLRgba(Style.rgba);
+end;
+
+function TBLContext.GetStrokeDashArray: TArray<Double>;
+begin
+  Result := TBLUtils.BLArrayToArray<Double>(FHandle.impl.state.strokeOptions.dashArray);
+end;
+
+function TBLContext.GetStrokeDashOffset: Double;
+begin
+  Result := FHandle.impl.state.strokeOptions.dashOffset;
+end;
+
+function TBLContext.GetStrokeEndCap: TBLStrokeCap;
+begin
+  Result := TBLStrokeCap(FHandle.impl.state.strokeOptions.options.endCap);
+end;
+
+function TBLContext.GetStrokeGradient: IBLGradient;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  Result := TBLGradient.Create(Style.gradient, True);
+end;
+
+function TBLContext.GetStrokeJoin: TBLStrokeJoin;
+begin
+  Result := TBLStrokeJoin(FHandle.impl.state.strokeOptions.options.join);
+end;
+
+function TBLContext.GetStrokeMiterLimit: Double;
+begin
+  Result := FHandle.impl.state.strokeOptions.miterLimit;
+end;
+
+function TBLContext.GetStrokeOptions: TBLStrokeOptions;
+begin
+  Result.FHandle := FHandle.impl.state.strokeOptions;
+end;
+
+function TBLContext.GetStrokePattern: IBLPattern;
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  Result := TBLPattern.Create(Style.pattern, True);
+end;
+
+function TBLContext.GetStrokeStartCap: TBLStrokeCap;
+begin
+  Result := TBLStrokeCap(FHandle.impl.state.strokeOptions.options.startCap);
+end;
+
+procedure TBLContext.GetStrokeStyle(out ARgba: TBLRgba64);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  ARgba.Reset(TBLRgba(Style.rgba));
+end;
+
+procedure TBLContext.GetStrokeStyle(out ARgba: TBLRgba32);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  ARgba.Reset(TBLRgba(Style.rgba));
+end;
+
+procedure TBLContext.GetStrokeStyle(out AGradient: IBLGradient);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  AGradient := TBLGradient.Create(Style.gradient, True);
+end;
+
+procedure TBLContext.GetStrokeStyle(out ARgba: TBLRgba);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  ARgba := TBLRgba(Style.rgba);
+end;
+
+procedure TBLContext.GetStrokeStyle(out APattern: IBLPattern);
+var
+  Style: BLStyleCore;
+begin
+  _BLCheck(blContextGetStrokeStyle(@FHandle, @Style));
+  APattern := TBLPattern.Create(Style.pattern, True);
+end;
+
+function TBLContext.GetStrokeStyle: TBLStyleType;
+begin
+  Result := TBLStyleType(FHandle.impl.state.styleType[BL_CONTEXT_OP_TYPE_STROKE]);
+end;
+
+function TBLContext.GetStrokeTransformOrder: TBLStrokeTransformOrder;
+begin
+  Result := TBLStrokeTransformOrder(FHandle.impl.state.strokeOptions.options.transformOrder);
+end;
+
+function TBLContext.GetStrokeWidth: Double;
+begin
+  Result := FHandle.impl.state.strokeOptions.width;
+end;
+
+function TBLContext.GetTargetHeight: Double;
+begin
+  Result := FHandle.impl.state.targetSize.h;
+end;
+
+function TBLContext.GetTargetImage: IBLImage;
+begin
+  if (FHandle.impl.state.targetImage = nil) then
+    Result := nil
+  else
+    Result := TBLImage.Create(FHandle.impl.state.targetImage^, True);
+end;
+
+function TBLContext.GetTargetSize: TBLSize;
+begin
+  Result.FHandle := FHandle.impl.state.targetSize;
+end;
+
+function TBLContext.GetTargetWidth: Double;
+begin
+  Result := FHandle.impl.state.targetSize.w;
+end;
+
+function TBLContext.GetUserMatrix: TBLMatrix2D;
+begin
+  Result.FHandle := FHandle.impl.state.userMatrix;
+end;
+
+procedure TBLContext.PostRotate(const AAngle: Double; const APoint: TBLPoint);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := APoint.FHandle.x;
+  Data[2] := APoint.FHandle.y;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLContext.PostRotate(const AAngle: Double;
+  const APoint: TBLPointI);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := APoint.FHandle.x;
+  Data[2] := APoint.FHandle.y;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLContext.PostRotate(const AAngle: Double);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE, @AAngle));
+end;
+
+procedure TBLContext.PostRotate(const AAngle, AX, AY: Double);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AX;
+  Data[2] := AY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_ROTATE_PT, @Data));
+end;
+
+procedure TBLContext.PostScale(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @Data));
+end;
+
+procedure TBLContext.PostScale(const AXY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AXY;
+  Data[1] := AXY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @Data));
+end;
+
+procedure TBLContext.PostScale(const APoint: TBLPoint);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @APoint));
+end;
+
+procedure TBLContext.PostScale(const APoint: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := APoint.FHandle.x;
+  Data[1] := APoint.FHandle.y;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SCALE, @Data));
+end;
+
+procedure TBLContext.PostSkew(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SKEW, @Data));
+end;
+
+procedure TBLContext.PostSkew(const APoint: TBLPoint);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_SKEW, @APoint));
+end;
+
+procedure TBLContext.PostTransform(const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSFORM, @AMatrix));
+end;
+
+procedure TBLContext.PostTranslate(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSLATE, @Data));
+end;
+
+procedure TBLContext.PostTranslate(const APoint: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := APoint.FHandle.x;
+  Data[1] := APoint.FHandle.y;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSLATE, @Data));
+end;
+
+procedure TBLContext.PostTranslate(const APoint: TBLPoint);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_POST_TRANSLATE, @APoint));
+end;
+
+function TBLContext.QueryAccumulatedErrorFlags: TBLContextErrorFlags;
+begin
+  _BLCheck(blContextQueryProperty(@FHandle,
+    BL_CONTEXT_PROPERTY_ACCUMULATED_ERROR_FLAGS, @Result));
+end;
+
+function TBLContext.QueryThreadCount: Integer;
+begin
+  _BLCheck(blContextQueryProperty(@FHandle, BL_CONTEXT_PROPERTY_THREAD_COUNT,
+    @Result));
+end;
+
+procedure TBLContext.Reset;
+begin
+  _BLCheck(blContextReset(@FHandle));
+end;
+
+procedure TBLContext.ResetMatrix;
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_RESET, nil));
+end;
+
+procedure TBLContext.Restore(const ACookie: TBLContextCookie);
+begin
+  _BLCheck(blContextRestore(@FHandle, @ACookie));
+end;
+
+procedure TBLContext.Restore;
+begin
+  _BLCheck(blContextRestore(@FHandle, nil));
+end;
+
+procedure TBLContext.RestoreClipping;
+begin
+  _BLCheck(blContextRestoreClipping(@FHandle));
+end;
+
+procedure TBLContext.Rotate(const AAngle: Double; const APoint: TBLPoint);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := APoint.FHandle.x;
+  Data[2] := APoint.FHandle.y;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLContext.Rotate(const AAngle, AX, AY: Double);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := AX;
+  Data[2] := AY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLContext.Rotate(const AAngle: Double);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE, @AAngle));
+end;
+
+procedure TBLContext.Rotate(const AAngle: Double; const APoint: TBLPointI);
+var
+  Data: array [0..2] of Double;
+begin
+  Data[0] := AAngle;
+  Data[1] := APoint.FHandle.x;
+  Data[2] := APoint.FHandle.y;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_ROTATE_PT, @Data));
+end;
+
+procedure TBLContext.Save(out ACookie: TBLContextCookie);
+begin
+  _BLCheck(blContextSave(@FHandle, @ACookie));
+end;
+
+procedure TBLContext.Save;
+begin
+  _BLCheck(blContextSave(@FHandle, nil));
+end;
+
+procedure TBLContext.Scale(const AXY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AXY;
+  Data[1] := AXY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @Data));
+end;
+
+procedure TBLContext.Scale(const APoint: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := APoint.FHandle.x;
+  Data[1] := APoint.FHandle.y;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @Data));
+end;
+
+procedure TBLContext.Scale(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @Data));
+end;
+
+procedure TBLContext.Scale(const APoint: TBLPoint);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_SCALE, @APoint));
+end;
+
+procedure TBLContext.SetCompOp(const AValue: TBLCompOp);
+begin
+  _BLCheck(blContextSetCompOp(@FHandle, Ord(AValue)));
+end;
+
+procedure TBLContext.SetFillAlpha(const AValue: Double);
+begin
+  _BLCheck(blContextSetFillAlpha(@FHandle, AValue));
+end;
+
+procedure TBLContext.SetFillColor(const AValue: TBLRgba32);
+begin
+  _BLCheck(blContextSetFillStyleRgba32(@FHandle, AValue.FHandle.value));
+end;
+
+procedure TBLContext.SetFillColor64(const AValue: TBLRgba64);
+begin
+  _BLCheck(blContextSetFillStyleRgba64(@FHandle, AValue.FHandle.value));
+end;
+
+procedure TBLContext.SetFillColorF(const AValue: TBLRgba);
+begin
+  _BLCheck(blContextSetFillStyleRgba(@FHandle, @AValue));
+end;
+
+procedure TBLContext.SetFillGradient(const AValue: IBLGradient);
+begin
+  if (AValue <> nil) then
+    _BLCheck(blContextSetFillStyleObject(@FHandle, AValue.Handle));
+end;
+
+procedure TBLContext.SetFillPattern(const AValue: IBLPattern);
+begin
+  if (AValue <> nil) then
+    _BLCheck(blContextSetFillStyleObject(@FHandle, AValue.Handle));
+end;
+
+procedure TBLContext.SetFillRule(const AValue: TBLFillRule);
+begin
+  _BLCheck(blContextSetFillRule(@FHandle, Ord(AValue)));
+end;
+
+procedure TBLContext.SetFillStyle(const ARgba: TBLRgba64);
+begin
+  _BLCheck(blContextSetFillStyleRgba64(@FHandle, ARgba.FHandle.value));
+end;
+
+procedure TBLContext.SetFillStyle(const ARgba: TBLRgba32);
+begin
+  _BLCheck(blContextSetFillStyleRgba32(@FHandle, ARgba.FHandle.value));
+end;
+
+procedure TBLContext.SetFillStyle(const APattern: IBLPattern);
+begin
+  if (APattern <> nil) then
+    _BLCheck(blContextSetFillStyleObject(@FHandle, APattern.Handle));
+end;
+
+procedure TBLContext.SetFillStyle(const AImage: IBLImage);
+begin
+  if (AImage <> nil) then
+    _BLCheck(blContextSetFillStyleObject(@FHandle, AImage.Handle));
+end;
+
+procedure TBLContext.SetFillStyle(const ARgba: TBLRgba);
+begin
+  _BLCheck(blContextSetFillStyleRgba(@FHandle, @ARgba));
+end;
+
+procedure TBLContext.SetFillStyle(const AGradient: IBLGradient);
+begin
+  if (AGradient <> nil) then
+    _BLCheck(blContextSetFillStyleObject(@FHandle, AGradient.Handle));
+end;
+
+procedure TBLContext.SetFlattenMode(const AValue: TBLFlattenMode);
+begin
+  _BLCheck(blContextSetFlattenMode(@FHandle, Ord(AValue)));
+end;
+
+procedure TBLContext.SetFlattenTolerance(const AValue: Double);
+begin
+  _BLCheck(blContextSetFlattenTolerance(@FHandle, AValue));
+end;
+
+procedure TBLContext.SetGlobalAlpha(const AValue: Double);
+begin
+  _BLCheck(blContextSetGlobalAlpha(@FHandle, AValue));
+end;
+
+procedure TBLContext.SetGradientQuality(const AValue: TBLGradientQuality);
+begin
+  _BLCheck(blContextSetHint(@FHandle, BL_CONTEXT_HINT_GRADIENT_QUALITY, Ord(AValue)));
+end;
+
+procedure TBLContext.SetHints(const AValue: TBLContextHints);
+begin
+  _BLCheck(blContextSetHints(@FHandle, @AValue.FHandle));
+end;
+
+procedure TBLContext.SetPatternQuality(const AValue: TBLPatternQuality);
+begin
+  _BLCheck(blContextSetHint(@FHandle, BL_CONTEXT_HINT_PATTERN_QUALITY, Ord(AValue)));
+end;
+
+procedure TBLContext.SetRenderingQuality(const AValue: TBLRenderingQuality);
+begin
+  _BLCheck(blContextSetHint(@FHandle, BL_CONTEXT_HINT_RENDERING_QUALITY, Ord(AValue)));
+end;
+
+procedure TBLContext.SetStrokeAlpha(const AValue: Double);
+begin
+  _BLCheck(blContextSetStrokeAlpha(@FHandle, AValue));
+end;
+
+procedure TBLContext.SetStrokeColor(const AValue: TBLRgba32);
+begin
+  _BLCheck(blContextSetStrokeStyleRgba32(@FHandle, AValue.FHandle.value));
+end;
+
+procedure TBLContext.SetStrokeColor64(const AValue: TBLRgba64);
+begin
+  _BLCheck(blContextSetStrokeStyleRgba64(@FHandle, AValue.FHandle.value));
+end;
+
+procedure TBLContext.SetStrokeColorF(const AValue: TBLRgba);
+begin
+  _BLCheck(blContextSetStrokeStyleRgba(@FHandle, @AValue));
+end;
+
+procedure TBLContext.SetStrokeDashArray(const AValue: TArray<Double>);
+var
+  Value: IBLArray;
+begin
+  Value := TBLUtils.ArrayToBLArray<Double>(AValue);
+  _BLCheck(blContextSetStrokeDashArray(@FHandle, Value.Handle));
+end;
+
+procedure TBLContext.SetStrokeDashOffset(const AValue: Double);
+begin
+  _BLCheck(blContextSetStrokeDashOffset(@FHandle, AValue));
+end;
+
+procedure TBLContext.SetStrokeEndCap(const AValue: TBLStrokeCap);
+begin
+  _BLCheck(blContextSetStrokeCap(@FHandle, BL_STROKE_CAP_POSITION_END, Ord(AValue)));
+end;
+
+procedure TBLContext.SetStrokeGradient(const AValue: IBLGradient);
+begin
+  if (AValue <> nil) then
+    _BLCheck(blContextSetStrokeStyleObject(@FHandle, AValue.Handle));
+end;
+
+procedure TBLContext.SetStrokeJoin(const AValue: TBLStrokeJoin);
+begin
+  _BLCheck(blContextSetStrokeJoin(@FHandle, Ord(AValue)));
+end;
+
+procedure TBLContext.SetStrokeMiterLimit(const AValue: Double);
+begin
+  _BLCheck(blContextSetStrokeMiterLimit(@FHandle, AValue));
+end;
+
+procedure TBLContext.SetStrokeOptions(const AValue: TBLStrokeOptions);
+begin
+  _BLCheck(blContextSetStrokeOptions(@FHandle, @AValue.FHandle));
+end;
+
+procedure TBLContext.SetStrokePattern(const AValue: IBLPattern);
+begin
+  if (AValue <> nil) then
+    _BLCheck(blContextSetStrokeStyleObject(@FHandle, AValue.Handle));
+end;
+
+procedure TBLContext.SetStrokeStartCap(const AValue: TBLStrokeCap);
+begin
+  _BLCheck(blContextSetStrokeCap(@FHandle, BL_STROKE_CAP_POSITION_START, Ord(AValue)));
+end;
+
+procedure TBLContext.SetStrokeStyle(const ARgba: TBLRgba64);
+begin
+  _BLCheck(blContextSetStrokeStyleRgba64(@FHandle, ARgba.FHandle.value));
+end;
+
+procedure TBLContext.SetStrokeStyle(const ARgba: TBLRgba32);
+begin
+  _BLCheck(blContextSetStrokeStyleRgba32(@FHandle, ARgba.FHandle.value));
+end;
+
+procedure TBLContext.SetStrokeStyle(const APattern: IBLPattern);
+begin
+  if (APattern <> nil) then
+    _BLCheck(blContextSetStrokeStyleObject(@FHandle, APattern.Handle));
+end;
+
+procedure TBLContext.SetStrokeStyle(const AGradient: IBLGradient);
+begin
+  if (AGradient <> nil) then
+    _BLCheck(blContextSetStrokeStyleObject(@FHandle, AGradient.Handle));
+end;
+
+procedure TBLContext.SetStrokeStyle(const AImage: IBLImage);
+begin
+  if (AImage <> nil) then
+    _BLCheck(blContextSetStrokeStyleObject(@FHandle, AImage.Handle));
+end;
+
+procedure TBLContext.SetStrokeStyle(const ARgba: TBLRgba);
+begin
+  _BLCheck(blContextSetStrokeStyleRgba(@FHandle, @ARgba));
+end;
+
+procedure TBLContext.SetStrokeTransformOrder(
+  const AValue: TBLStrokeTransformOrder);
+begin
+  _BLCheck(blContextSetStrokeTransformOrder(@FHandle, Ord(AValue)));
+end;
+
+procedure TBLContext.SetStrokeWidth(const AValue: Double);
+begin
+  _BLCheck(blContextSetStrokeWidth(@FHandle, AValue));
+end;
+
+procedure TBLContext.SetUserMatrix(const AValue: TBLMatrix2D);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_ASSIGN, @AValue));
+end;
+
+procedure TBLContext.Skew(const APoint: TBLPoint);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_SKEW, @APoint));
+end;
+
+procedure TBLContext.Skew(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_SKEW, @Data));
+end;
+
+procedure TBLContext.Start(const AImage: IBLImage;
+  const ACreateInfo: TBLContextCreateInfo);
+begin
+  if (AImage <> nil) then
+    _BLCheck(blContextBegin(@FHandle, AImage.Handle, @ACreateInfo.FHandle));
+end;
+
+procedure TBLContext.Start(const AImage: IBLImage);
+begin
+  if (AImage <> nil) then
+    _BLCheck(blContextBegin(@FHandle, AImage.Handle, nil));
+end;
+
+procedure TBLContext.StrokeArc(const AArc: TBLArc);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ARC, @AArc));
+end;
+
+procedure TBLContext.StrokeArc(const ACX, ACY, AR, AStart, ASweep: Double);
+var
+  Arc: TBLArc;
+begin
+  Arc.Reset(ACX, ACY, AR, AStart, ASweep);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ARC, @Arc));
+end;
+
+procedure TBLContext.StrokeArc(const ACX, ACY, ARX, ARY, AStart,
+  ASweep: Double);
+var
+  Arc: TBLArc;
+begin
+  Arc.Reset(ACX, ACY, ARX, ARY, AStart, ASweep);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ARC, @Arc));
+end;
+
+procedure TBLContext.StrokeBox(const AX0, AY0, AX1, AY1: Double);
+var
+  Box: TBLBox;
+begin
+  Box.Reset(AX0, AY0, AX1, AY1);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_BOXD, @Box));
+end;
+
+procedure TBLContext.StrokeBox(const ABox: TBLBox);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_BOXD, @ABox));
+end;
+
+procedure TBLContext.StrokeBox(const ABox: TBLBoxI);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_BOXI, @ABox));
+end;
+
+procedure TBLContext.StrokeBoxArray(const ABoxes: PBLBoxI;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLBoxI>;
+begin
+  View.Reset(ABoxes, ACount);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @View));
+end;
+
+procedure TBLContext.StrokeBoxArray(const ABoxes: PBLBox;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLBox>;
+begin
+  View.Reset(ABoxes, ACount);
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @View));
+end;
+
+procedure TBLContext.StrokeBoxArray(const ABoxes: TBLArrayView<TBLBox>);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @ABoxes));
+end;
+
+procedure TBLContext.StrokeBoxArray(const ABoxes: TBLArrayView<TBLBoxI>);
+begin
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @ABoxes));
+end;
+
+procedure TBLContext.StrokeBoxArray(const ABoxes: TArray<TBLBoxI>);
+var
+  View: TBLArrayView<TBLBoxI>;
+begin
+  View.Reset(Pointer(ABoxes), Length(ABoxes));
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, @View));
+end;
+
+procedure TBLContext.StrokeBoxArray(const ABoxes: TArray<TBLBox>);
+var
+  View: TBLArrayView<TBLBox>;
+begin
+  View.Reset(Pointer(ABoxes), Length(ABoxes));
+  _BLCheck(blContextFillGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, @View));
+end;
+
+procedure TBLContext.StrokeChord(const AChord: TBLArc);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_CHORD, @AChord));
+end;
+
+procedure TBLContext.StrokeChord(const ACX, ACY, AR, AStart, ASweep: Double);
+var
+  Chord: TBLArc;
+begin
+  Chord.Reset(ACX, ACY, AR, AStart, ASweep);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_CHORD, @Chord));
+end;
+
+procedure TBLContext.StrokeChord(const ACX, ACY, ARX, ARY, AStart,
+  ASweep: Double);
+var
+  Chord: TBLArc;
+begin
+  Chord.Reset(ACX, ACY, ARX, ARY, AStart, ASweep);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_CHORD, @Chord));
+end;
+
+procedure TBLContext.StrokeCircle(const ACX, ACY, AR: Double);
+var
+  Circle: TBLCircle;
+begin
+  Circle.Reset(ACX, ACY, AR);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_CIRCLE, @Circle));
+end;
+
+procedure TBLContext.StrokeCircle(const ACircle: TBLCircle);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_CIRCLE, @ACircle));
+end;
+
+procedure TBLContext.StrokeEllipse(const AEllipse: TBLEllipse);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ELLIPSE, @AEllipse));
+end;
+
+procedure TBLContext.StrokeEllipse(const ACX, ACY, ARX, ARY: Double);
+var
+  Ellipse: TBLEllipse;
+begin
+  Ellipse.Reset(ACX, ACY, ARX, ARY);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ELLIPSE, @Ellipse));
+end;
+
+procedure TBLContext.StrokeGlyphRun(const ADst: TBLPointI; const AFont: IBLFont;
+  const AGlyphRun: TBLGlyphRun);
+var
+  Font: PBLFontCore;
+begin
+  if (AFont = nil) then
+    Font := nil
+  else
+    Font := AFont.Handle;
+
+  _BLCheck(blContextStrokeGlyphRunI(@FHandle, @ADst, Font, @AGlyphRun));
+end;
+
+procedure TBLContext.StrokeGlyphRun(const ADst: TBLPoint; const AFont: IBLFont;
+  const AGlyphRun: TBLGlyphRun);
+var
+  Font: PBLFontCore;
+begin
+  if (AFont = nil) then
+    Font := nil
+  else
+    Font := AFont.Handle;
+
+  _BLCheck(blContextStrokeGlyphRunD(@FHandle, @ADst, Font, @AGlyphRun));
+end;
+
+procedure TBLContext.StrokeLine(const AX0, AY0, AX1, AY1: Double);
+var
+  Line: TBLLine;
+begin
+  Line.Reset(AX0, AY0, AX1, AY1);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_LINE, @Line));
+end;
+
+procedure TBLContext.StrokeLine(const AP0, AP1: TBLPoint);
+var
+  Line: TBLLine;
+begin
+  Line.Reset(AP0, AP1);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_LINE, @Line));
+end;
+
+procedure TBLContext.StrokeLine(const ALine: TBLLine);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_LINE, @ALine));
+end;
+
+procedure TBLContext.StrokePath(const APath: IBLPath);
+begin
+  if (APath <> nil) then
+    _BLCheck(blContextStrokePathD(@FHandle, APath.Handle));
+end;
+
+procedure TBLContext.StrokePie(const ACX, ACY, ARX, ARY, AStart,
+  ASweep: Double);
+var
+  Pie: TBLArc;
+begin
+  Pie.Reset(ACX, ACY, ARX, ARY, AStart, ASweep);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_PIE, @Pie));
+end;
+
+procedure TBLContext.StrokePie(const ACX, ACY, AR, AStart, ASweep: Double);
+var
+  Pie: TBLArc;
+begin
+  Pie.Reset(ACX, ACY, AR, AStart, ASweep);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_PIE, @Pie));
+end;
+
+procedure TBLContext.StrokePie(const APie: TBLArc);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_PIE, @APie));
+end;
+
+procedure TBLContext.StrokePolygon(const APoly: TBLArrayView<TBLPoint>);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @APoly));
+end;
+
+procedure TBLContext.StrokePolygon(const APoly: TArray<TBLPointI>);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(Pointer(APoly), Length(APoly));
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @View));
+end;
+
+procedure TBLContext.StrokePolygon(const APoly: PBLPoint;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(APoly, ACount);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @View));
+end;
+
+procedure TBLContext.StrokePolygon(const APoly: TArray<TBLPoint>);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(Pointer(APoly), Length(APoly));
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGOND, @View));
+end;
+
+procedure TBLContext.StrokePolygon(const APoly: PBLPointI;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(APoly, ACount);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @View));
+end;
+
+procedure TBLContext.StrokePolygon(const APoly: TBLArrayView<TBLPointI>);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYGONI, @APoly));
+end;
+
+procedure TBLContext.StrokePolyline(const APoly: TBLArrayView<TBLPointI>);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINEI, @APoly));
+end;
+
+procedure TBLContext.StrokePolyline(const APoly: TArray<TBLPoint>);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(Pointer(APoly), Length(APoly));
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINED, @APoly));
+end;
+
+procedure TBLContext.StrokePolyline(const APoly: TBLArrayView<TBLPoint>);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINED, @APoly));
+end;
+
+procedure TBLContext.StrokePolyline(const APoly: PBLPoint;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLPoint>;
+begin
+  View.Reset(APoly, ACount);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINED, @APoly));
+end;
+
+procedure TBLContext.StrokePolyline(const APoly: TArray<TBLPointI>);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(Pointer(APoly), Length(APoly));
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINEI, @APoly));
+end;
+
+procedure TBLContext.StrokePolyline(const APoly: PBLPointI;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLPointI>;
+begin
+  View.Reset(APoly, ACount);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_POLYLINEI, @APoly));
+end;
+
+procedure TBLContext.StrokeRect(const ARect: TBLRectI);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_RECTI, @ARect));
+end;
+
+procedure TBLContext.StrokeRect(const ARect: TBLRect);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_RECTD, @ARect));
+end;
+
+procedure TBLContext.StrokeRect(const AX, AY, AW, AH: Double);
+var
+  Rect: TBLRect;
+begin
+  Rect.Reset(AX, AY, AW, AH);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_RECTD, @Rect));
+end;
+
+procedure TBLContext.StrokeRectArray(const ARects: PBLRect;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLRect>;
+begin
+  View.Reset(ARects, ACount);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @View));
+end;
+
+procedure TBLContext.StrokeRectArray(const ARects: TArray<TBLRect>);
+var
+  View: TBLArrayView<TBLRect>;
+begin
+  View.Reset(Pointer(ARects), Length(ARects));
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @View));
+end;
+
+procedure TBLContext.StrokeRectArray(const ARects: TBLArrayView<TBLRect>);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, @ARects));
+end;
+
+procedure TBLContext.StrokeRectArray(const ARects: TBLArrayView<TBLRectI>);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @ARects));
+end;
+
+procedure TBLContext.StrokeRectArray(const ARects: PBLRectI;
+  const ACount: Integer);
+var
+  View: TBLArrayView<TBLRectI>;
+begin
+  View.Reset(ARects, ACount);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @View));
+end;
+
+procedure TBLContext.StrokeRectArray(const ARects: TArray<TBLRectI>);
+var
+  View: TBLArrayView<TBLRectI>;
+begin
+  View.Reset(Pointer(ARects), Length(ARects));
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, @View));
+end;
+
+procedure TBLContext.StrokeRoundRect(const AX, AY, AW, AH, AR: Double);
+var
+  RoundRect: TBLRoundRect;
+begin
+  RoundRect.Reset(AX, AY, AW, AH, AR);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @RoundRect));
+end;
+
+procedure TBLContext.StrokeRoundRect(const ARect: TBLRect; const AR: Double);
+var
+  RoundRect: TBLRoundRect;
+begin
+  RoundRect.Reset(ARect, AR);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @RoundRect));
+end;
+
+procedure TBLContext.StrokeRoundRect(const ARoundRect: TBLRoundRect);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @ARoundRect));
+end;
+
+procedure TBLContext.StrokeRoundRect(const ARect: TBLRect; const ARX,
+  ARY: Double);
+var
+  RoundRect: TBLRoundRect;
+begin
+  RoundRect.Reset(ARect, ARX, ARY);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @RoundRect));
+end;
+
+procedure TBLContext.StrokeRoundRect(const AX, AY, AW, AH, ARX, ARY: Double);
+var
+  RoundRect: TBLRoundRect;
+begin
+  RoundRect.Reset(AX, AY, AW, AH, ARX, ARY);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_ROUND_RECT, @RoundRect));
+end;
+
+procedure TBLContext.StrokeText(const ADst: TBLPoint; const AFont: IBLFont;
+  const AText: UCS4String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> nil) then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextStrokeTextD(@FHandle, @ADst, Font, Pointer(AText), Length(AText) - 1, BL_TEXT_ENCODING_UTF32));
+  end;
+end;
+
+procedure TBLContext.StrokeText(const ADst: TBLPoint; const AFont: IBLFont;
+  const AText: UTF8String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> '') then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextStrokeTextD(@FHandle, @ADst, Font, Pointer(AText), Length(AText), BL_TEXT_ENCODING_UTF8));
+  end;
+end;
+
+procedure TBLContext.StrokeText(const ADst: TBLPointI; const AFont: IBLFont;
+  const AText: UCS4String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> nil) then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextStrokeTextI(@FHandle, @ADst, Font, Pointer(AText), Length(AText) - 1, BL_TEXT_ENCODING_UTF32));
+  end;
+end;
+
+procedure TBLContext.StrokeText(const ADst: TBLPointI; const AFont: IBLFont;
+  const AText: UTF8String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> '') then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextStrokeTextI(@FHandle, @ADst, Font, Pointer(AText), Length(AText), BL_TEXT_ENCODING_UTF8));
+  end;
+end;
+
+procedure TBLContext.StrokeText(const ADst: TBLPoint; const AFont: IBLFont;
+  const AText: String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> '') then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextStrokeTextD(@FHandle, @ADst, Font, Pointer(AText), Length(AText), BL_TEXT_ENCODING_UTF16));
+  end;
+end;
+
+procedure TBLContext.StrokeText(const ADst: TBLPointI; const AFont: IBLFont;
+  const AText: String);
+var
+  Font: PBLFontCore;
+begin
+  if (AText <> '') then
+  begin
+    if (AFont = nil) then
+      Font := nil
+    else
+      Font := AFont.Handle;
+
+    _BLCheck(blContextStrokeTextI(@FHandle, @ADst, Font, Pointer(AText), Length(AText), BL_TEXT_ENCODING_UTF16));
+  end;
+end;
+
+procedure TBLContext.StrokeTriangle(const ATriangle: TBLTriangle);
+begin
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_TRIANGLE, @ATriangle));
+end;
+
+procedure TBLContext.StrokeTriangle(const AX0, AY0, AX1, AY1, AX2, AY2: Double);
+var
+  Triangle: TBLTriangle;
+begin
+  Triangle.Reset(AX0, AY0, AX1, AY1, AX2, AY2);
+  _BLCheck(blContextStrokeGeometry(@FHandle, BL_GEOMETRY_TYPE_TRIANGLE, @Triangle));
+end;
+
+procedure TBLContext.Transform(const AMatrix: TBLMatrix2D);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSFORM, @AMatrix));
+end;
+
+procedure TBLContext.Translate(const APoint: TBLPointI);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := APoint.FHandle.x;
+  Data[1] := APoint.FHandle.y;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSLATE, @Data));
+end;
+
+procedure TBLContext.Translate(const AX, AY: Double);
+var
+  Data: array [0..1] of Double;
+begin
+  Data[0] := AX;
+  Data[1] := AY;
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSLATE, @Data));
+end;
+
+procedure TBLContext.Translate(const APoint: TBLPoint);
+begin
+  _BLCheck(blContextMatrixOp(@FHandle, BL_MATRIX2D_OP_TRANSLATE, @APoint));
+end;
+
+procedure TBLContext.UserToMeta;
+begin
+  _BLCheck(blContextUserToMeta(@FHandle));
+end;
+
+{$ENDREGION 'Context'}
+
+{$REGION 'Runtime'}
+
+{ TBLRuntimeBuildInfo }
+
+function TBLRuntimeBuildInfo.GetBaselineCpuFeatures: TBLRuntimeCpuFeatures;
+begin
+  Byte(Result) := FHandle.baselineCpuFeatures;
+end;
+
+function TBLRuntimeBuildInfo.GetBuildType: TBLRuntimeBuildType;
+begin
+  Result := TBLRuntimeBuildType(FHandle.buildType);
+end;
+
+function TBLRuntimeBuildInfo.GetSupportedCpuFeatures: TBLRuntimeCpuFeatures;
+begin
+  Byte(Result) := FHandle.supportedCpuFeatures;
+end;
+
+{ TBLRuntimeSystemInfo }
+
+function TBLRuntimeSystemInfo.GetCpuArch: TBLRuntimeCpuArch;
+begin
+  Result := TBLRuntimeCpuArch(FHandle.cpuArch);
+end;
+
+function TBLRuntimeSystemInfo.GetCpuFeatures: TBLRuntimeCpuFeatures;
+begin
+  Byte(Result) := FHandle.cpuFeatures;
+end;
+
+{ TBLRuntime }
+
+class procedure TBLRuntime.Cleanup(const AFlags: TBLRuntimeCleanupFlags);
+begin
+  _BLCheck(blRuntimeCleanup(Byte(AFlags)));
+end;
+
+class procedure TBLRuntime.LogMessage(const AMessage: String;
+  const AArgs: array of const);
+begin
+  _BLCheck(blRuntimeMessageOut(MarshaledAString(UTF8String(Format(AMessage, AArgs)))));
+end;
+
+class procedure TBLRuntime.LogMessage(const AMessage: String);
+begin
+  _BLCheck(blRuntimeMessageOut(MarshaledAString(UTF8String(AMessage))));
+end;
+
+class procedure TBLRuntime.QueryBuildInfo(out AInfo: TBLRuntimeBuildInfo);
+begin
+  _BLCheck(blRuntimeQueryInfo(BL_RUNTIME_INFO_TYPE_BUILD, @AInfo));
+end;
+
+class procedure TBLRuntime.QueryResourceInfo(out AInfo: TBLRuntimeResourceInfo);
+begin
+  _BLCheck(blRuntimeQueryInfo(BL_RUNTIME_INFO_TYPE_RESOURCE, @AInfo));
+end;
+
+class procedure TBLRuntime.QuerySystemInfo(out AInfo: TBLRuntimeSystemInfo);
+begin
+  _BLCheck(blRuntimeQueryInfo(BL_RUNTIME_INFO_TYPE_SYSTEM, @AInfo));
+end;
+
+{$ENDREGION 'Runtime'}
+
+{$REGION 'Internal'}
+
+procedure _BLCheck(const AResult: BLResultCode);
+begin
+  if (AResult <> BL_SUCCESS) and Assigned(GErrorHandler) then
+    GErrorHandler(TBLResultCode(AResult), GErrorUserData);
+end;
+
+{$ENDREGION 'Internal'}
+
+{$REGION 'Initialization'}
+initialization
+  BLSetExceptionErrorHandler;
+
+{$ENDREGION 'Initialization'}
+
+end.

+ 18 - 0
Externals/Graphics32/Examples/Drawing/Benchmark/DelphiBlend2D - License.txt

@@ -0,0 +1,18 @@
+Copyright (c) 2017-2020, The Blend2D Team
+Copyright (c) 2020 by Erik van Bilsen
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution. 

+ 277 - 0
Externals/Graphics32/Examples/Drawing/Benchmark/GR32_Polygons.Blend2D.pas

@@ -0,0 +1,277 @@
+unit GR32_Polygons.Blend2D;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is Blend2D Polygon Rasterizer for Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Anders Melander
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2025
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+{$IFDEF FPC}
+{$DEFINE PUREPASCAL}
+{$ENDIF}
+
+
+uses
+  Types,
+
+  // Requires DelphiBlend2D
+  // https://github.com/neslib/DelphiBlend2D
+  Blend2D,
+
+  GR32,
+  GR32_Polygons;
+
+//------------------------------------------------------------------------------
+//
+// TPolygonRenderer32Blend2D
+//
+//------------------------------------------------------------------------------
+// Blend2D polygon rasterizer.
+//------------------------------------------------------------------------------
+// Note: The Filler property of TPolygonRenderer32 is ignored; Fills are always
+// solid.
+//------------------------------------------------------------------------------
+type
+//  TPolygonRenderer32Blend2D = class(TPolygonRenderer32)
+  TPolygonRenderer32Blend2D = class(TPolygonRenderer32, IPolygonRendererBatching)
+  private
+    FImage: IBLImage;
+    FContext: IBLContext;
+    FBatchLevel: integer;
+    FInnerBatchLevel: integer;
+
+  private
+    procedure InnerBeginDraw;
+    procedure InnerEndDraw;
+
+  protected
+    procedure SetBitmap(const Value: TCustomBitmap32); override;
+    procedure SetColor(const Value: TColor32); override;
+    procedure SetFillMode(const Value: TPolyFillMode); override;
+
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+
+    procedure BeginDraw;
+    procedure EndDraw;
+
+    procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect); override;
+  end;
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+
+implementation
+
+uses
+  Math,
+  SysUtils,
+
+  GR32_VectorUtils,
+  GR32_Backends;
+
+//------------------------------------------------------------------------------
+//
+// TPolygonRenderer32Blend2D
+//
+//------------------------------------------------------------------------------
+constructor TPolygonRenderer32Blend2D.Create;
+begin
+  inherited Create;
+  FContext := TBLContext.Create;
+end;
+
+destructor TPolygonRenderer32Blend2D.Destroy;
+begin
+  FImage := nil;
+  FContext := nil;
+
+  inherited;
+end;
+
+//------------------------------------------------------------------------------
+
+procedure TPolygonRenderer32Blend2D.BeginDraw;
+begin
+  Inc(FBatchLevel);
+
+  if (FBatchLevel = 1) and (FImage <> nil) then
+    FContext.Start(FImage);
+end;
+
+procedure TPolygonRenderer32Blend2D.EndDraw;
+begin
+  Dec(FBatchLevel);
+
+  if (FBatchLevel = 0) and (FImage <> nil) then
+    FContext.Finish;
+end;
+
+//------------------------------------------------------------------------------
+
+procedure TPolygonRenderer32Blend2D.InnerBeginDraw;
+const
+  b2dFillMode: array[TPolyFillMode] of TBLFillRule = (TBLFillRule.EvenOdd, TBLFillRule.NonZero);
+begin
+  BeginDraw;
+
+  Inc(FInnerBatchLevel);
+
+  if (FInnerBatchLevel = 1) then
+  begin
+    FContext.FillColor := Color;
+    FContext.FillRule := b2dFillMode[FillMode];
+  end;
+end;
+
+procedure TPolygonRenderer32Blend2D.InnerEndDraw;
+begin
+  Dec(FInnerBatchLevel);
+  EndDraw;
+end;
+
+//------------------------------------------------------------------------------
+
+procedure TPolygonRenderer32Blend2D.SetBitmap(const Value: TCustomBitmap32);
+begin
+  if (Value = Bitmap) then
+    exit;
+
+  Assert(FInnerBatchLevel = 0, 'Cannot alter state inside InnerBeginDraw/InnerEndDraw');
+
+  if (FImage <> nil) then
+  begin
+    if (FBatchLevel > 0) then
+      FContext.Finish;
+
+    FImage := nil;
+  end;
+
+  inherited;
+
+  if (Bitmap <> nil) then
+  begin
+    FImage := TBLImage.Create;
+    FImage.InitializeFromData(Bitmap.Width, Bitmap.Height, TBLFormat.PRGB32, Bitmap.Bits, Bitmap.Width*SizeOf(TColor32));
+
+    if (FBatchLevel > 0) then
+      FContext.Start(FImage);
+  end;
+end;
+
+//------------------------------------------------------------------------------
+
+procedure TPolygonRenderer32Blend2D.SetColor(const Value: TColor32);
+begin
+  if (Value = Color) then
+    exit;
+
+  Assert(FInnerBatchLevel = 0, 'Cannot alter state inside InnerBeginDraw/InnerEndDraw');
+
+  inherited;
+end;
+
+procedure TPolygonRenderer32Blend2D.SetFillMode(const Value: TPolyFillMode);
+begin
+  if (Value = FillMode) then
+    exit;
+
+  Assert(FInnerBatchLevel = 0, 'Cannot alter state inside InnerBeginDraw/InnerEndDraw');
+
+  inherited;
+end;
+
+//------------------------------------------------------------------------------
+
+type
+  TBitmap32Access = class(TBitmap32);
+
+procedure TPolygonRenderer32Blend2D.PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
+var
+  i, j: Integer;
+  Path: IBLPath;
+{$IFDEF CHANGENOTIFICATIONS}
+  ChangeRect: TRect;
+{$ENDIF}
+begin
+  if (Length(Points) = 0) then
+    Exit;
+
+  if (FImage = nil) then
+    exit;
+
+  if (not Bitmap.MeasuringMode) then
+  begin
+    InnerBeginDraw;
+
+    Path := TBLPath.Create;
+
+    for j := 0 to High(Points) do
+      if (Length(Points[j]) > 1) then
+      begin
+        Path.MoveTo(Points[j, 0].X, Points[j, 0].Y);
+        for i := 1 to High(Points[j]) do
+          Path.LineTo(Points[j, i].X, Points[j, i].Y);
+        Path.Close;
+      end;
+
+    FContext.FillPath(Path);
+
+    Path := nil;
+
+    InnerEndDraw;
+  end;
+
+{$IFDEF CHANGENOTIFICATIONS}
+  if (TBitmap32Access(Bitmap).LockUpdateCount = 0) and
+    ((Bitmap.MeasuringMode) or (TBitmap32Access(Bitmap).UpdateCount = 0)) then
+  begin
+    for i := 0 to High(Points) do
+      if (Length(Points[i]) > 1) then
+      begin
+        if (GR32.IntersectRect(ChangeRect, MakeRect(ClipRect, rrOutside), MakeRect(PolygonBounds(Points[i])))) then
+          Bitmap.Changed(ChangeRect);
+      end;
+  end;
+{$ENDIF}
+end;
+
+//------------------------------------------------------------------------------
+
+initialization
+  RegisterPolygonRenderer(TPolygonRenderer32Blend2D);
+
+end.

+ 202 - 0
Externals/Graphics32/Examples/Drawing/Benchmark/MainUnit.dfm

@@ -0,0 +1,202 @@
+object MainForm: TMainForm
+  Left = 324
+  Top = 77
+  Caption = 'Polygon Renderer Benchmark'
+  ClientHeight = 612
+  ClientWidth = 754
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Segoe UI'
+  Font.Style = []
+  Position = poScreenCenter
+  ShowHint = True
+  OnCreate = FormCreate
+  OnShow = FormShow
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 0
+    Top = 373
+    Width = 754
+    Height = 5
+    Cursor = crVSplit
+    Align = alBottom
+    AutoSnap = False
+    Beveled = True
+    ResizeStyle = rsUpdate
+    ExplicitTop = 350
+    ExplicitWidth = 746
+  end
+  object PnlTop: TPanel
+    Left = 0
+    Top = 0
+    Width = 754
+    Height = 373
+    Align = alClient
+    BevelOuter = bvNone
+    BorderWidth = 10
+    TabOrder = 0
+    object Img: TImage32
+      Left = 10
+      Top = 10
+      Width = 734
+      Height = 353
+      Align = alClient
+      Bitmap.ResamplerClassName = 'TNearestResampler'
+      BitmapAlign = baTopLeft
+      Scale = 1.000000000000000000
+      ScaleMode = smNormal
+      TabOrder = 0
+      OnResize = ImgResize
+    end
+  end
+  object PnlBottom: TPanel
+    Left = 0
+    Top = 378
+    Width = 754
+    Height = 234
+    Align = alBottom
+    BevelOuter = bvNone
+    BorderWidth = 10
+    TabOrder = 1
+    object GbxSettings: TGroupBox
+      Left = 10
+      Top = 10
+      Width = 319
+      Height = 214
+      Align = alLeft
+      Caption = 'Benchmark Settings'
+      TabOrder = 0
+      DesignSize = (
+        319
+        214)
+      object LblTest: TLabel
+        Left = 14
+        Top = 34
+        Width = 23
+        Height = 13
+        Caption = '&Test:'
+        Color = clBtnFace
+        FocusControl = CmbTest
+        ParentColor = False
+        Transparent = False
+      end
+      object LblRenderer: TLabel
+        Left = 14
+        Top = 61
+        Width = 50
+        Height = 13
+        Caption = '&Renderer:'
+        Color = clBtnFace
+        FocusControl = CmbRenderer
+        ParentColor = False
+        Transparent = False
+      end
+      object BtnBenchmark: TButton
+        Left = 14
+        Top = 178
+        Width = 139
+        Height = 25
+        Caption = 'Do &Benchmark'
+        TabOrder = 4
+        OnClick = BtnBenchmarkClick
+      end
+      object CmbTest: TComboBox
+        Left = 78
+        Top = 31
+        Width = 225
+        Height = 21
+        Style = csDropDownList
+        TabOrder = 0
+      end
+      object CmbRenderer: TComboBox
+        Left = 78
+        Top = 58
+        Width = 225
+        Height = 21
+        Style = csDropDownList
+        TabOrder = 1
+      end
+      object CbxAllTests: TCheckBox
+        Left = 14
+        Top = 98
+        Width = 167
+        Height = 19
+        Caption = 'Benchmark all tests'
+        TabOrder = 2
+      end
+      object CbxAllRenderers: TCheckBox
+        Left = 14
+        Top = 118
+        Width = 167
+        Height = 19
+        Caption = 'Benchmark all renderers'
+        TabOrder = 3
+      end
+      object BtnExit: TButton
+        Left = 164
+        Top = 178
+        Width = 139
+        Height = 25
+        Caption = 'E&xit'
+        TabOrder = 5
+        OnClick = BtnExitClick
+      end
+      object CheckBoxBatch: TCheckBox
+        Left = 14
+        Top = 138
+        Width = 167
+        Height = 19
+        Hint = 'Enable batching for renderers that support it'
+        Caption = 'Enable batching'
+        TabOrder = 6
+      end
+    end
+    object GbxResults: TGroupBox
+      Left = 339
+      Top = 10
+      Width = 405
+      Height = 214
+      Align = alClient
+      Caption = 'Benchmark Res&ults'
+      TabOrder = 1
+      object PnlBenchmark: TPanel
+        Left = 2
+        Top = 15
+        Width = 401
+        Height = 197
+        Align = alClient
+        BevelOuter = bvNone
+        BorderWidth = 10
+        TabOrder = 0
+        object MemoLog: TMemo
+          Left = 10
+          Top = 10
+          Width = 381
+          Height = 177
+          Align = alClient
+          Font.Charset = ANSI_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Courier New'
+          Font.Pitch = fpFixed
+          Font.Style = []
+          ParentFont = False
+          ScrollBars = ssVertical
+          TabOrder = 0
+          WordWrap = False
+        end
+      end
+    end
+    object PnlSpacer: TPanel
+      Left = 329
+      Top = 10
+      Width = 10
+      Height = 214
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 2
+    end
+  end
+end

+ 670 - 0
Externals/Graphics32/Examples/Drawing/Benchmark/MainUnit.pas

@@ -0,0 +1,670 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is GR32 Polygon Renderer Benchmark
+ *
+ * The Initial Developer of the Original Code is
+ * Mattias Andersson <[email protected]>
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+(*
+** Define TEST_BLEND2D to enable the Blend2D polygon rasterizer.
+**
+** The Blend2D rasterizer requires the Blend2D DLL files which can be
+** downloaded from https://github.com/neslib/DelphiBlend2D/tree/master/Bin
+*)
+{-$define TEST_BLEND2D}
+
+(*
+** Define TEST_LCD to enable the VPR LCD polygon rasterizers (ClearType style anti-aliasing).
+*)
+{-$define TEST_LCD}
+
+uses
+{$ifdef MSWINDOWS}
+  Windows, Messages,
+{$endif}
+  SysUtils, Classes, Graphics, StdCtrls, Controls, Forms, Dialogs, ExtCtrls,
+  GR32_Image,
+  GR32_Paths,
+  GR32,
+  GR32_System,
+  GR32_Brushes,
+  GR32_Polygons;
+
+const
+  // Run <TEST_SAMPLES> iterations, each taking <TEST_DURATION> milliseconds.
+  // Use the best result of all samles as the final result.
+  TEST_DURATION = 4000;
+  TEST_SAMPLES = 4;
+
+{$ifdef MSWINDOWS}
+const
+  MSG_BENCHMARK = WM_USER;
+{$endif}
+
+type
+  TTestProc = procedure(Canvas: TCanvas32; FillBrush: TSolidBrush; StrokeBrush: TStrokeBrush);
+
+  { TMainForm }
+
+  TMainForm = class(TForm)
+    BtnBenchmark: TButton;
+    BtnExit: TButton;
+    CbxAllRenderers: TCheckBox;
+    CbxAllTests: TCheckBox;
+    CmbRenderer: TComboBox;
+    CmbTest: TComboBox;
+    GbxResults: TGroupBox;
+    GbxSettings: TGroupBox;
+    Img: TImage32;
+    LblRenderer: TLabel;
+    LblTest: TLabel;
+    MemoLog: TMemo;
+    PnlBenchmark: TPanel;
+    PnlBottom: TPanel;
+    PnlSpacer: TPanel;
+    PnlTop: TPanel;
+    Splitter1: TSplitter;
+    CheckBoxBatch: TCheckBox;
+    procedure FormCreate(Sender: TObject);
+    procedure BtnBenchmarkClick(Sender: TObject);
+    procedure ImgResize(Sender: TObject);
+    procedure BtnExitClick(Sender: TObject);
+    procedure FormShow(Sender: TObject);
+  private
+    procedure RunTest(RendererClass: TPolygonRenderer32Class; TestProc: TTestProc; Samples: integer = TEST_SAMPLES; TestTime: integer = TEST_DURATION);
+    procedure WriteTestResult(OperationsPerSecond: Integer);
+{$ifdef MSWINDOWS}
+    procedure MsgBenchmark(var Msg: TMessage); message MSG_BENCHMARK;
+{$endif}
+  end;
+
+var
+  MainForm: TMainForm;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Types,
+  Math,
+  GR32_VectorUtils,
+  GR32_LowLevel,
+  GR32_Resamplers,
+  GR32_Backends,
+  GR32_VPR2,
+  GR32_Polygons.GDI,
+{$ifndef FPC}
+  GR32_Polygons.GDIPlus,
+  GR32_Polygons.Direct2D,
+{$ifdef TEST_BLEND2D}
+  GR32_Polygons.Blend2D,
+{$endif TEST_BLEND2D}
+{$endif}
+  GR32_Polygons.AggLite;
+
+var
+  TestRegistry: TStringList;
+
+procedure RegisterTest(const TestName: string; Test: TTestProc);
+begin
+  if not Assigned(TestRegistry) then
+    TestRegistry := TStringList.Create;
+  TestRegistry.AddObject(TestName, TObject(@Test));
+end;
+
+procedure TMainForm.WriteTestResult(OperationsPerSecond: Integer);
+begin
+  MemoLog.Lines.Add(Format('%-40s %8.0n', [cmbRenderer.Text, OperationsPerSecond*1.0]));
+end;
+
+procedure TMainForm.RunTest(RendererClass: TPolygonRenderer32Class; TestProc: TTestProc; Samples, TestTime: integer);
+var
+  Canvas: TCanvas32;
+  FillBrush: TSolidBrush;
+  StrokeBrush: TStrokeBrush;
+  StopWatch: TStopWatch;
+  WallClock: TStopWatch;
+  i: integer;
+  Operations: Int64;
+  PolygonRendererBatching: IPolygonRendererBatching;
+  Sample: integer;
+  OpsPerSecond: integer;
+  BestOpsPerSecond: integer;
+  DoAbort: boolean;
+begin
+  RandSeed := 0;
+
+  Canvas := TCanvas32.Create(Img.Bitmap);
+  try
+    Canvas.Renderer := RendererClass.Create;
+
+    try
+      Img.BeginUpdate;
+      try
+        Img.Bitmap.Clear(clWhite32);
+
+        FillBrush := Canvas.Brushes.Add(TSolidBrush) as TSolidBrush;
+        StrokeBrush := Canvas.Brushes.Add(TStrokeBrush) as TStrokeBrush;
+        FillBrush.Visible := True;
+        StrokeBrush.Visible := False;
+
+        DoAbort := False;
+        BestOpsPerSecond := 0;
+
+        for Sample := 0 to Samples-1 do
+        begin
+
+          Operations := 0;
+          Wallclock := TStopwatch.StartNew;
+          StopWatch.Reset;
+
+          repeat
+
+            // If the rasterizer supports batching, we allow it to batch a block.
+            // This might give batching rasterizers a slight unrealistic and
+            // unfair advantage. One rasterizer that absolutely suffer, if we don't
+            // batch, is the Direct2D rasterizer.
+            if (CheckBoxBatch.Checked) and (Supports(Canvas.Renderer, IPolygonRendererBatching, PolygonRendererBatching)) then
+            begin
+              StopWatch.Start;
+              PolygonRendererBatching.BeginDraw;
+              StopWatch.Stop;
+            end;
+            try
+
+              for i := 0 to 9 do
+              begin
+                Canvas.BeginUpdate;
+
+                // Build path
+                TestProc(Canvas, FillBrush, StrokeBrush);
+
+                StopWatch.Start;
+
+                // Flatten path and render
+                Canvas.EndUpdate;
+
+                StopWatch.Stop;
+
+                Inc(Operations);
+              end;
+
+            finally
+              if (PolygonRendererBatching <> nil) then
+              begin
+                StopWatch.Start;
+                // For batching rasterizers, this is usually where the actual work will be done
+                PolygonRendererBatching.EndDraw;
+                StopWatch.Stop;
+              end;
+            end;
+
+          until (Wallclock.ElapsedMilliseconds > TestTime);
+
+          OpsPerSecond := (Operations * 1000) div StopWatch.ElapsedMilliseconds;
+
+          if (OpsPerSecond > BestOpsPerSecond) then
+            BestOpsPerSecond := OpsPerSecond;
+
+          if (GetAsyncKeyState(VK_ESCAPE) <> 0) then
+          begin
+            DoAbort := False;
+            break;
+          end;
+        end;
+
+        WriteTestResult(BestOpsPerSecond);
+
+{$IFNDEF CHANGENOTIFICATIONS}
+        Img.Bitmap.Changed;
+{$ENDIF}
+      finally
+        Img.EndUpdate;
+      end;
+
+      if (DoAbort) or (GetAsyncKeyState(VK_ESCAPE) <> 0) then
+      begin
+        MemoLog.Lines.Add('Aborted');
+        Abort;
+      end;
+
+      Application.ProcessMessages; // Avoid Windows thinking we're hung and freezing UI
+
+    except
+      on E: EAbort do
+        raise;
+
+      on E: Exception do
+        MemoLog.Lines.Add(Format('%s: Failed', [cmbRenderer.Text]));
+    end;
+  finally
+    Canvas.Free;
+  end;
+end;
+
+function RandColor: TColor32; {$IFDEF USEINLINING} inline; {$ENDIF}
+begin
+  Result := Random($FFFFFF) or Random($ff) shl 24;
+end;
+
+//----------------------------------------------------------------------------//
+// ellipses
+//----------------------------------------------------------------------------//
+procedure EllipseTest(Canvas: TCanvas32; FillBrush: TSolidBrush; StrokeBrush: TStrokeBrush);
+var
+  W, H: Integer;
+begin
+  W := Canvas.Bitmap.Width;
+  H := Canvas.Bitmap.Height;
+
+  FillBrush.FillColor := RandColor;
+  FillBrush.FillMode := pfNonZero;
+  StrokeBrush.Visible := False;
+
+  Canvas.Ellipse(Random(W), Random(H), Random(W shr 1), Random(H shr 1));
+end;
+
+//----------------------------------------------------------------------------//
+// thin lines
+//----------------------------------------------------------------------------//
+procedure ThinLineTest(Canvas: TCanvas32; FillBrush: TSolidBrush; StrokeBrush: TStrokeBrush);
+var
+  W, H: Integer;
+begin
+  W := Canvas.Bitmap.Width;
+  H := Canvas.Bitmap.Height;
+
+  FillBrush.Visible := False;
+  StrokeBrush.Visible := True;
+  StrokeBrush.StrokeWidth := 1.0;
+  StrokeBrush.FillColor := RandColor;
+
+  Canvas.MoveTo(Random(W), Random(H));
+  Canvas.LineTo(Random(W), Random(H));
+  Canvas.EndPath;
+end;
+
+//----------------------------------------------------------------------------//
+// thick lines
+//----------------------------------------------------------------------------//
+procedure ThickLineTest(Canvas: TCanvas32; FillBrush: TSolidBrush; StrokeBrush: TStrokeBrush);
+var
+  W, H: Integer;
+begin
+  W := Canvas.Bitmap.Width;
+  H := Canvas.Bitmap.Height;
+
+  FillBrush.Visible := False;
+  StrokeBrush.Visible := True;
+  StrokeBrush.StrokeWidth := 10.0;
+  StrokeBrush.FillColor := RandColor;
+
+  Canvas.MoveTo(Random(W), Random(H));
+  Canvas.LineTo(Random(W), Random(H));
+  Canvas.EndPath;
+end;
+
+//----------------------------------------------------------------------------//
+// text
+//----------------------------------------------------------------------------//
+const
+  STRINGS: array [0..5] of string = (
+    'Graphics32',
+    'Excellence endures!',
+    'Hello World!',
+    'Lorem ipsum dolor sit amet, consectetur adipisicing elit,' + #13#10 +
+    'sed do eiusmod tempor incididunt ut labore et dolore magna' + #13#10 +
+    'aliqua. Ut enim ad minim veniam, quis nostrud exercitation' + #13#10 +
+    'ullamco laboris nisi ut aliquip ex ea commodo consequat.',
+    'The quick brown fox jumps over the lazy dog.',
+    'Jackdaws love my big sphinx of quartz.');
+
+type
+  TFontEntry = record
+    Name: string;
+    Size: Integer;
+    Style: TFontStyles;
+  end;
+
+const
+  FACES: array [0..5] of TFontEntry = (
+    (Name: 'Trebuchet MS'; Size: 24; Style: [fsBold]),
+    (Name: 'Tahoma'; Size: 20; Style: [fsItalic]),
+    (Name: 'Courier New'; Size: 14; Style: []),
+    (Name: 'Georgia'; Size: 8; Style: [fsItalic]),
+    (Name: 'Times New Roman'; Size: 12; Style: []),
+    (Name: 'Garamond'; Size: 12; Style: [])
+  );
+
+procedure TextTest(Canvas: TCanvas32; FillBrush: TSolidBrush; StrokeBrush: TStrokeBrush);
+var
+  W, H, I: Integer;
+  Font: TFont;
+begin
+  W := Canvas.Bitmap.Width;
+  H := Canvas.Bitmap.Height;
+
+  FillBrush.Visible := True;
+  FillBrush.FillMode := pfAlternate;
+  FillBrush.FillColor := RandColor;
+  StrokeBrush.Visible := False;
+
+  I := Random(5);
+  Font := Canvas.Bitmap.Font;
+  Font.Name := FACES[I].Name;
+  Font.Size := FACES[I].Size;
+  Font.Style := FACES[I].Style;
+
+  Canvas.RenderText(Random(W), Random(H), STRINGS[I]);
+end;
+
+//----------------------------------------------------------------------------//
+// splines
+//----------------------------------------------------------------------------//
+function MakeCurve(const Points: TArrayOfFloatPoint; Kernel: TCustomKernel;
+  Closed: Boolean; StepSize: Integer): TArrayOfFloatPoint;
+var
+  I, J, F, H, Index, LastIndex, Steps, R: Integer;
+  K, V, W, X, Y: TFloat;
+  Delta: TFloatPoint;
+  Filter: TFilterMethod;
+  WrapProc: TWrapProc;
+  PPoint: PFloatPoint;
+const
+  WRAP_PROC: array[Boolean] of TWrapProc = (Clamp, Wrap);
+begin
+  WrapProc := Wrap_PROC[Closed];
+  Filter := Kernel.Filter;
+  R := Ceil(Kernel.GetWidth);
+  H := High(Points);
+
+  LastIndex := H - Ord(not Closed);
+  Steps := 0;
+  for I := 0 to LastIndex do
+  begin
+    Index := WrapProc(I + 1, H);
+    Delta.X := Points[Index].X - Points[I].X;
+    Delta.Y := Points[Index].Y - Points[I].Y;
+    Inc(Steps, Floor(Hypot(Delta.X, Delta.Y) / StepSize) + 1);
+  end;
+
+  SetLength(Result, Steps);
+  PPoint := @Result[0];
+
+  for I := 0 to LastIndex do
+  begin
+    Index := WrapProc(I + 1, H);
+    Delta.X := Points[Index].X - Points[I].X;
+    Delta.Y := Points[Index].Y - Points[I].Y;
+    Steps := Floor(Hypot(Delta.X, Delta.Y) / StepSize);
+    if Steps > 0 then
+    begin
+      K := 1 / Steps;
+      V := 0;
+      for J := 0 to Steps do
+      begin
+        X := 0; Y := 0;
+        for F := -R to R do
+        begin
+          Index := WrapProc(I - F, H);
+          W := Filter(F + V);
+          X := X + W * Points[Index].X;
+          Y := Y + W * Points[Index].Y;
+        end;
+        PPoint^ := FloatPoint(X, Y);
+        Inc(PPoint);
+        V := V + K;
+      end;
+    end;
+  end;
+end;
+
+procedure SplinesTest(Canvas: TCanvas32; FillBrush: TSolidBrush; StrokeBrush: TStrokeBrush);
+var
+  Input, Points: TArrayOfFloatPoint;
+  K: TSplineKernel;
+  W, H, I: Integer;
+begin
+  W := Canvas.Bitmap.Width;
+  H := Canvas.Bitmap.Height;
+  SetLength(Input, 10);
+  for I := 0 to High(Input) do
+  begin
+    Input[I].X := Random(W);
+    Input[I].Y := Random(H);
+  end;
+  K := TSplineKernel.Create;
+  try
+    Points := MakeCurve(Input, K, True, 3);
+  finally
+    K.Free;
+  end;
+
+  FillBrush.Visible := True;
+  FillBrush.FillMode := pfEvenOdd;
+  FillBrush.FillColor := RandColor;
+  StrokeBrush.Visible := False;
+
+  Canvas.Polygon(Points);
+end;
+
+//----------------------------------------------------------------------------//
+
+procedure TMainForm.FormCreate(Sender: TObject);
+begin
+  // set priority class and thread priority for better accuracy
+{$ifdef MSWINDOWS}
+  SetPriorityClass(GetCurrentProcess, HIGH_PRIORITY_CLASS);
+  SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_HIGHEST);
+{$endif}
+
+  CmbTest.Items := TestRegistry;
+  CmbTest.ItemIndex := 0;
+  PolygonRendererList.GetClassNames(CmbRenderer.Items);
+  CmbRenderer.ItemIndex := 0;
+  Img.SetupBitmap(True, clWhite32);
+end;
+
+
+procedure TMainForm.FormShow(Sender: TObject);
+begin
+{$ifdef MSWINDOWS}
+  if (FindCmdLineSwitch('benchmark')) then
+    PostMessage(Handle, MSG_BENCHMARK, 0, 0);
+{$endif}
+end;
+
+{$ifdef MSWINDOWS}
+procedure TMainForm.MsgBenchmark(var Msg: TMessage);
+var
+  Iterations: integer;
+  i: integer;
+{$if defined(FRAMEWORK_VCL)}
+  s: string;
+{$ifend}
+begin
+  (*
+  ** Detect and initiate automated benchmark for profiling
+  *)
+
+{$if defined(FRAMEWORK_VCL)}
+  if (not FindCmdLineSwitch('benchmark', s)) then
+    exit;
+  Iterations := StrToIntDef(s, 1);
+{$else}
+  if (not FindCmdLineSwitch('benchmark')) then
+    exit;
+  Iterations := 1;
+{$ifend}
+
+  Screen.Cursor := crHourGlass;
+
+  MemoLog.Lines.Add(Format('Running benchmark: %d iterations', [Iterations]));
+
+  CbxAllTests.Checked := True;
+
+  for i := 0 to Iterations-1 do
+  begin
+    MemoLog.Lines.Add(Format('Iteration %d', [i+1]));
+    Update;
+
+    BtnBenchmark.Click;
+  end;
+
+  Application.Terminate;
+end;
+{$endif}
+
+procedure TMainForm.BtnBenchmarkClick(Sender: TObject);
+
+  procedure TestRenderer(RendererClass: TPolygonRenderer32Class);
+  begin
+    RunTest(RendererClass, TTestProc(cmbTest.Items.Objects[cmbTest.ItemIndex]));
+  end;
+
+  procedure TestAllRenderers;
+  var
+    I: Integer;
+    RendererClass: TPolygonRenderer32Class;
+  begin
+    for I := 0 to CmbRenderer.Items.Count - 1 do
+    begin
+      CmbRenderer.ItemIndex := I;
+      RendererClass := TPolygonRenderer32Class(PolygonRendererList[CmbRenderer.ItemIndex]);
+      TestRenderer(RendererClass);
+    end;
+    MemoLog.Lines.Add('');
+  end;
+
+  procedure PerformTest;
+  var
+    RendererClass: TPolygonRenderer32Class;
+  begin
+    MemoLog.Lines.Add(Format('=== Test: %s (operations/second) ===', [cmbTest.Text]));
+    if CbxAllRenderers.Checked then
+      TestAllRenderers
+    else
+    begin
+      RendererClass := TPolygonRenderer32Class(PolygonRendererList[CmbRenderer.ItemIndex]);
+      TestRenderer(RendererClass);
+    end;
+  end;
+
+  procedure PerformAllTests;
+  var
+    I: Integer;
+  begin
+    for I := 0 to CmbTest.Items.Count - 1 do
+    begin
+      CmbTest.ItemIndex := I;
+      Update;
+      PerformTest;
+    end;
+    MemoLog.Lines.Add('');
+  end;
+
+begin
+  Screen.Cursor := crHourGlass;
+  try
+    Img.Bitmap.Clear(clWhite32);
+    Update;
+
+    // We are calling Application.ProcessMessages inside the test loop
+    // so disable form to avoid UI recursion.
+    Enabled := False;
+    try
+
+      if CbxAllTests.Checked then
+        PerformAllTests
+      else
+        PerformTest;
+
+    finally
+      Enabled := True;
+    end;
+
+  finally
+    Screen.Cursor := crDefault;
+  end;
+end;
+
+function CreateLine(const x1, y1, x2, y2, width: TFloat): TArrayOfFloatPoint;
+var
+  dx, dy, d: TFloat;
+begin
+  dx := x2 - x1;
+  dy := y2 - y1;
+  d := Sqrt(Sqr(dx) + Sqr(dy));
+  if d <> 0 then
+  begin
+    dx := width * (y2 - y1) / d;
+    dy := width * (x2 - x1) / d;
+    SetLength(Result, 4);
+    Result[0] := FloatPoint(x1 - dx, y1 + dy);
+    Result[1] := FloatPoint(x2 - dx, y2 + dy);
+    Result[2] := FloatPoint(x2 + dx, y2 - dy);
+    Result[3] := FloatPoint(x1 + dx, y1 - dy);
+  end
+  else
+  begin
+    SetLength(Result, 2);
+    Result[0] := FloatPoint(x1, y1);
+    Result[1] := FloatPoint(x2, y2);
+  end;
+end;
+
+procedure TMainForm.ImgResize(Sender: TObject);
+begin
+  Img.SetupBitmap(True, clWhite32);
+end;
+
+procedure TMainForm.BtnExitClick(Sender: TObject);
+begin
+  Close;
+end;
+
+initialization
+{$if not defined(TEST_LCD)}
+  // We're not interested in the ClearType rasterizers
+  UnregisterPolygonRenderer(TPolygonRenderer32LCD);
+  UnregisterPolygonRenderer(TPolygonRenderer32LCD2);
+{$ifend}
+
+  RegisterTest('Ellipses', EllipseTest);
+  RegisterTest('Thin Lines', ThinLineTest);
+  RegisterTest('Thick Lines', ThickLineTest);
+  RegisterTest('Splines', SplinesTest);
+  if Assigned(TBitmap32.GetPlatformBackendClass.GetInterfaceEntry(ITextToPathSupport)) then
+    RegisterTest('Text', TextTest);
+
+end.

+ 1 - 0
Externals/Graphics32/Examples/Drawing/Benchmark/Media.rc

@@ -0,0 +1 @@
+MainIcon ICON "../../Media/GR32.ico"

+ 16 - 0
Externals/Graphics32/Examples/Drawing/Blurs/Blurs.dpr

@@ -0,0 +1,16 @@
+program Blurs;
+
+{$R 'Media.res' 'Media.rc'}
+{$R 'mainicon.res' '..\..\mainicon.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+{.$R '..\..\manifest.res'}
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFrmBlurs, FrmBlurs);
+  Application.Run;
+end.

+ 170 - 0
Externals/Graphics32/Examples/Drawing/Blurs/Blurs.dproj

@@ -0,0 +1,170 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>Blurs.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{8f3c0339-6d95-461b-8a3d-8a0edbe5d967}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">Blurs</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>Blurs</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <RcCompile Include="..\..\mainicon.rc">
+            <Form>mainicon.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">Blurs.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 309 - 0
Externals/Graphics32/Examples/Drawing/Blurs/MainUnit.dfm

@@ -0,0 +1,309 @@
+object FrmBlurs: TFrmBlurs
+  Left = 283
+  Top = 189
+  Caption = 'Blurs'
+  ClientHeight = 405
+  ClientWidth = 719
+  Color = clBtnFace
+  Font.Charset = ANSI_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -12
+  Font.Name = 'Arial'
+  Font.Style = []
+  Menu = MainMenu
+  OnCreate = FormCreate
+  OnDestroy = FormDestroy
+  TextHeight = 15
+  object PnlControl: TPanel
+    Left = 0
+    Top = 0
+    Width = 154
+    Height = 382
+    Align = alLeft
+    BevelOuter = bvNone
+    ParentBackground = False
+    TabOrder = 0
+    object RgpBlurType: TRadioGroup
+      Left = 0
+      Top = 0
+      Width = 154
+      Height = 116
+      Align = alTop
+      Caption = 'Blur Type'
+      ItemIndex = 0
+      Items.Strings = (
+        '&None'
+        '&Gaussian'
+        '&Motion'
+        '&Selective')
+      ParentBackground = False
+      TabOrder = 0
+      OnClick = RgpBlurTypeClick
+    end
+    object PanelSelective: TPanel
+      Left = 0
+      Top = 181
+      Width = 154
+      Height = 46
+      Align = alTop
+      AutoSize = True
+      BevelOuter = bvNone
+      ParentBackground = False
+      TabOrder = 1
+      object LabelDelta: TLabel
+        Left = 0
+        Top = 0
+        Width = 54
+        Height = 15
+        Align = alTop
+        Caption = 'Delta (10)'
+        FocusControl = TrackBarDelta
+      end
+      object TrackBarDelta: TTrackBar
+        Left = 0
+        Top = 15
+        Width = 154
+        Height = 31
+        Align = alTop
+        Max = 255
+        PageSize = 10
+        Position = 10
+        TabOrder = 0
+        TickMarks = tmBoth
+        TickStyle = tsNone
+        OnChange = TrackBarDeltaChange
+      end
+    end
+    object PanelMotion: TPanel
+      Left = 0
+      Top = 227
+      Width = 154
+      Height = 65
+      Align = alTop
+      AutoSize = True
+      BevelOuter = bvNone
+      ParentBackground = False
+      TabOrder = 2
+      object LblBlurAngle: TLabel
+        Left = 0
+        Top = 0
+        Width = 80
+        Height = 15
+        Align = alTop
+        Caption = 'Blur &Angle (45)'
+        Enabled = False
+        FocusControl = TbrBlurAngle
+      end
+      object TbrBlurAngle: TTrackBar
+        Left = 0
+        Top = 15
+        Width = 154
+        Height = 31
+        Align = alTop
+        Enabled = False
+        Max = 180
+        Min = -180
+        Position = 45
+        TabOrder = 0
+        TickStyle = tsNone
+        OnChange = TbrBlurAngleChange
+      end
+      object CbxBidirectional: TCheckBox
+        Left = 0
+        Top = 46
+        Width = 154
+        Height = 19
+        Align = alTop
+        Caption = 'Bi&directional motion'
+        Checked = True
+        Enabled = False
+        State = cbChecked
+        TabOrder = 1
+        OnClick = PageControlChange
+      end
+    end
+    object PanelRadius: TPanel
+      Left = 0
+      Top = 116
+      Width = 154
+      Height = 65
+      Align = alTop
+      AutoSize = True
+      BevelOuter = bvNone
+      ParentBackground = False
+      TabOrder = 3
+      object LblBlurRadius: TLabel
+        Left = 0
+        Top = 0
+        Width = 90
+        Height = 15
+        Align = alTop
+        Caption = 'Blur &Radius (10)'
+        FocusControl = TbrBlurRadius
+      end
+      object TbrBlurRadius: TTrackBar
+        Left = 0
+        Top = 15
+        Width = 154
+        Height = 31
+        Align = alTop
+        Max = 50
+        Position = 10
+        TabOrder = 0
+        TickMarks = tmBoth
+        TickStyle = tsNone
+        OnChange = TbrBlurRadiusChange
+      end
+      object CheckBoxCorrectGamma: TCheckBox
+        Left = 0
+        Top = 46
+        Width = 154
+        Height = 19
+        Align = alTop
+        Caption = '&Correct Gamma'
+        Checked = True
+        State = cbChecked
+        TabOrder = 1
+        OnClick = PageControlChange
+      end
+    end
+  end
+  object SbrMain: TStatusBar
+    Left = 0
+    Top = 382
+    Width = 719
+    Height = 23
+    Panels = <>
+    SimplePanel = True
+  end
+  object PageControl: TPageControl
+    Left = 154
+    Top = 0
+    Width = 565
+    Height = 382
+    ActivePage = TabSheet1
+    Align = alClient
+    TabOrder = 2
+    OnChange = PageControlChange
+    object TabSheet1: TTabSheet
+      Caption = 'Page &1'
+      object ImgViewPage1: TImgView32
+        Left = 0
+        Top = 0
+        Width = 557
+        Height = 354
+        Align = alClient
+        Bitmap.ResamplerClassName = 'TNearestResampler'
+        BitmapAlign = baCustom
+        Scale = 1.000000000000000000
+        ScaleMode = smScale
+        Background.CheckersStyle = bcsMedium
+        Background.FillStyle = bfsCheckers
+        MousePan.Enabled = True
+        MouseZoom.Enabled = True
+        MouseZoom.Animate = True
+        ScrollBars.Increment = 0
+        ScrollBars.Size = 16
+        ScrollBars.Visibility = svAuto
+        OverSize = 0
+        TabOrder = 0
+      end
+    end
+    object TabSheet2: TTabSheet
+      Caption = 'Page &2'
+      ImageIndex = 1
+      object ImgViewPage2: TImgView32
+        Left = 0
+        Top = 0
+        Width = 557
+        Height = 354
+        Align = alClient
+        Bitmap.ResamplerClassName = 'TNearestResampler'
+        BitmapAlign = baCustom
+        Scale = 1.000000000000000000
+        ScaleMode = smScale
+        ScrollBars.Increment = 0
+        ScrollBars.Size = 16
+        ScrollBars.Visibility = svHidden
+        OverSize = 0
+        TabOrder = 0
+      end
+    end
+    object TabSheet3: TTabSheet
+      Caption = 'Page &3'
+      ImageIndex = 2
+      object ImgViewPage3: TImgView32
+        Left = 0
+        Top = 0
+        Width = 557
+        Height = 354
+        Align = alClient
+        Bitmap.DrawMode = dmBlend
+        Bitmap.ResamplerClassName = 'TNearestResampler'
+        BitmapAlign = baCustom
+        Scale = 1.000000000000000000
+        ScaleMode = smScale
+        Background.CheckersStyle = bcsMedium
+        Background.FillStyle = bfsCheckers
+        ScrollBars.Increment = 0
+        ScrollBars.Size = 16
+        ScrollBars.Visibility = svHidden
+        OverSize = 0
+        TabOrder = 0
+      end
+    end
+  end
+  object MainMenu: TMainMenu
+    Left = 188
+    Top = 116
+    object MnuFile: TMenuItem
+      Caption = '&File'
+      object MnuOpen: TMenuItem
+        Caption = '&Open ...'
+        OnClick = MnuOpenClick
+      end
+      object N1: TMenuItem
+        Caption = '-'
+      end
+      object MnuExit: TMenuItem
+        Caption = 'E&xit'
+        ShortCut = 27
+        OnClick = MnuExitClick
+      end
+    end
+    object MnuBlurType: TMenuItem
+      Caption = 'Bl&ur Type'
+      object MnuNone: TMenuItem
+        Caption = '&None'
+        OnClick = MnuGaussianTypeClick
+      end
+      object MnuGaussianType: TMenuItem
+        Caption = '&Gaussian'
+        Checked = True
+        OnClick = MnuGaussianTypeClick
+      end
+      object MnuMotion: TMenuItem
+        Caption = '&Motion'
+        OnClick = MnuGaussianTypeClick
+      end
+      object MnuSelective: TMenuItem
+        Caption = '&Selective'
+        OnClick = MnuGaussianTypeClick
+      end
+    end
+  end
+  object OpenDialog: TOpenDialog
+    DefaultExt = '.jpg'
+    Filter = 'Image Files (*.jpg;*.bmp)|*.jpg;*.bmp;'
+    Options = [ofHideReadOnly, ofFileMustExist, ofEnableSizing]
+    Left = 188
+    Top = 56
+  end
+  object TimerUpdate: TTimer
+    Enabled = False
+    Interval = 200
+    OnTimer = TimerUpdateTimer
+    Left = 188
+    Top = 180
+  end
+end

+ 448 - 0
Externals/Graphics32/Examples/Drawing/Blurs/MainUnit.pas

@@ -0,0 +1,448 @@
+unit MainUnit;
+
+{$include GR32.inc}
+
+interface
+
+uses
+  {$IFNDEF FPC} Windows, {$ELSE} LCLIntf, LCLType, {$ENDIF}
+  SysUtils, Classes, Graphics, Controls, Forms, Menus, Dialogs, ComCtrls,
+  ExtCtrls, StdCtrls, Math,
+  GR32,
+  GR32_Image,
+  GR32_Layers;
+
+type
+  TFrmBlurs = class(TForm)
+    MnuBlurType: TMenuItem;
+    CbxBidirectional: TCheckBox;
+    MnuFile: TMenuItem;
+    ImgViewPage1: TImgView32;
+    ImgViewPage2: TImgView32;
+    ImgViewPage3: TImgView32;
+    LblBlurAngle: TLabel;
+    LblBlurRadius: TLabel;
+    MainMenu: TMainMenu;
+    MnuExit: TMenuItem;
+    MnuGaussianType: TMenuItem;
+    MnuMotion: TMenuItem;
+    MnuNone: TMenuItem;
+    N1: TMenuItem;
+    MnuOpen: TMenuItem;
+    OpenDialog: TOpenDialog;
+    PageControl: TPageControl;
+    PnlControl: TPanel;
+    RgpBlurType: TRadioGroup;
+    SbrMain: TStatusBar;
+    TabSheet1: TTabSheet;
+    TabSheet2: TTabSheet;
+    TabSheet3: TTabSheet;
+    TbrBlurAngle: TTrackBar;
+    TbrBlurRadius: TTrackBar;
+    CheckBoxCorrectGamma: TCheckBox;
+    LabelDelta: TLabel;
+    TrackBarDelta: TTrackBar;
+    PanelSelective: TPanel;
+    MnuSelective: TMenuItem;
+    PanelMotion: TPanel;
+    TimerUpdate: TTimer;
+    PanelRadius: TPanel;
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+    procedure MnuExitClick(Sender: TObject);
+    procedure MnuGaussianTypeClick(Sender: TObject);
+    procedure MnuOpenClick(Sender: TObject);
+    procedure PageControlChange(Sender: TObject);
+    procedure RgpBlurTypeClick(Sender: TObject);
+    procedure TbrBlurAngleChange(Sender: TObject);
+    procedure TbrBlurRadiusChange(Sender: TObject);
+    procedure TrackBarDeltaChange(Sender: TObject);
+    procedure TimerUpdateTimer(Sender: TObject);
+  private
+    FBitmapStoneWeed: TBitmap32;
+    FBitmapIceland: TBitmap32;
+    FBitmapRandBox: TBitmap32;
+    FLayerBitmap: TBitmapLayer;
+
+    FRedrawFlag: Boolean;
+
+    procedure Redraw;
+    procedure QueueUpdate;
+
+  end;
+
+var
+  FrmBlurs: TFrmBlurs;
+
+implementation
+
+uses
+{$if defined(UseInlining)}
+  Types,
+{$ifend}
+  GR32.ImageFormats.JPG,
+  GR32_Polygons,
+  GR32_VectorUtils,
+  GR32_System,
+  GR32.Blur,
+  GR32.Blur.SelectiveGaussian,
+  GR32_Blurs;
+
+{$R *.dfm}
+
+const
+  GaussianBlurSimple: array [Boolean] of TBlurFunction = (Blur32, GammaBlur32);
+  GaussianBlurBounds: array [Boolean] of TBlurFunctionBounds = (Blur32, GammaBlur32);
+  GaussianBlurRegion: array [Boolean] of TBlurFunctionRegion = (Blur32, GammaBlur32);
+
+{ Miscellaneous functions }
+
+procedure DrawFramedBox(Bmp32: TBitmap32; const Rec: TRect;
+  Color1, Color2: TColor32; LineWidth: TFloat);
+var
+  Pts: TArrayOfFloatPoint;
+begin
+  if LineWidth < 1 then
+    LineWidth := 1;
+  SetLength(Pts, 6);
+
+  Pts[0] := FloatPoint(Rec.Left, Rec.Bottom);
+  Pts[1] := FloatPoint(Rec.Left, Rec.Top);
+  Pts[2] := FloatPoint(Rec.Right, Rec.Top);
+  Pts[3] := FloatPoint(Rec.Right - LineWidth, Rec.Top + LineWidth);
+  Pts[4] := FloatPoint(Rec.Left + LineWidth, Rec.Top + LineWidth);
+  Pts[5] := FloatPoint(Rec.Left + LineWidth, Rec.Bottom - LineWidth);
+  PolygonFS(Bmp32, Pts, Color1);
+
+  Pts[1] := FloatPoint(Rec.Right, Rec.Bottom);
+  Pts[2] := FloatPoint(Rec.Right, Rec.Top);
+  Pts[3] := FloatPoint(Rec.Right - LineWidth, Rec.Top + LineWidth);
+  Pts[4] := FloatPoint(Rec.Right - LineWidth, Rec.Bottom - LineWidth);
+  Pts[5] := FloatPoint(Rec.Left + LineWidth, Rec.Bottom - LineWidth);
+  PolygonFS(Bmp32, Pts, Color2);
+end;
+
+{ TFrmBlurs }
+
+procedure TFrmBlurs.FormCreate(Sender: TObject);
+var
+  X, Y: Integer;
+const
+  Colors: array [0 .. 21] of TColor32 = (clAliceBlue32, clAquamarine32,
+    clAzure32, clBeige32, clBlueViolet32, clCadetblue32, clChocolate32,
+    clCoral32, clCornFlowerBlue32, clCornSilk32, clCrimson32,
+    clDarkBlue32, clDarkCyan32, clDarkGoldenRod32, clDarkGreen32,
+    clDarkMagenta32, clDarkOrange32, clDarkOrchid32, clDarkRed32,
+    clDarkSalmon32, clDarkSeaGreen32, clDarkSlateBlue32);
+begin
+  FBitmapStoneWeed := TBitmap32.create;
+  FBitmapStoneWeed.DrawMode := dmBlend;
+  FBitmapStoneWeed.LoadFromResourceName(hInstance, 'STONEWEED', RT_RCDATA);
+
+  FBitmapIceland := TBitmap32.create;
+  FBitmapIceland.DrawMode := dmBlend;
+  FBitmapIceland.LoadFromResourceName(hInstance, 'ICELAND', RT_RCDATA);
+
+  Randomize;
+  FBitmapRandBox := TBitmap32.create;
+  // Generate an image of full of random, semi-transparent, colored boxes ...
+  FBitmapRandBox.SetSize(192, 272);
+  for X := 0 to 11 do
+    for Y := 0 to 16 do
+      FBitmapRandBox.FillRectS(X * 16, Y * 16, 300 + (X + 1) * 16,
+        40 + (Y + 1) * 16, SetAlpha(Colors[Random(22)], 128));
+
+  FLayerBitmap := TBitmapLayer(ImgViewPage3.Layers.Add(TBitmapLayer));
+  FLayerBitmap.Bitmap.DrawMode := dmBlend;
+
+  RgpBlurType.ItemIndex := 1;
+
+{$ifndef FPC}
+  PnlControl.Padding.Left := 8;
+  PnlControl.Padding.Right := 8;
+  PnlControl.Padding.Top := 8;
+  PnlControl.Padding.Bottom := 8;
+  PanelSelective.Padding.Top := 8;
+  PanelMotion.Padding.Top := 8;
+  PanelRadius.Padding.Top := 8;
+{$else}
+  PnlControl.BorderSpacing.Around := 8;
+  PanelSelective.BorderSpacing.Top := 8;
+  PanelMotion.BorderSpacing.Top := 8;
+  PanelRadius.BorderSpacing.Top := 8;
+{$endif}
+end;
+
+procedure TFrmBlurs.FormDestroy(Sender: TObject);
+begin
+  FBitmapStoneWeed.Free;
+  FBitmapIceland.Free;
+  FBitmapRandBox.Free;
+end;
+
+procedure TFrmBlurs.Redraw;
+var
+  Radius: Integer;
+  Rec, Rec2: TRect;
+  Pts, Pts2: TArrayOfFloatPoint;
+  WithGamma: Boolean;
+  Stopwatch: TStopwatch;
+begin
+  if FRedrawFlag then
+    Exit;
+
+  FRedrawFlag := True;
+  try
+
+    Screen.Cursor := crHourGlass;
+
+    Radius := TbrBlurRadius.Position;
+    WithGamma := CheckBoxCorrectGamma.Checked;
+    case PageControl.ActivePageIndex of
+      0:
+        begin
+          ImgViewPage1.BeginUpdate;
+          try
+            ImgViewPage1.Bitmap.Assign(FBitmapIceland);
+
+            Stopwatch := TStopwatch.StartNew;
+            case RgpBlurType.ItemIndex of
+              1:
+                GaussianBlurSimple[WithGamma](ImgViewPage1.Bitmap, Radius);
+
+              2:
+                if WithGamma then
+                  MotionBlurGamma(ImgViewPage1.Bitmap, Radius, TbrBlurAngle.Position, CbxBidirectional.Checked)
+                else
+                  MotionBlur(ImgViewPage1.Bitmap, Radius, TbrBlurAngle.Position, CbxBidirectional.Checked);
+
+              3:
+                if WithGamma then
+                  GammaSelectiveGaussianBlur32(FBitmapIceland, ImgViewPage1.Bitmap, Radius, TrackBarDelta.Position)
+                else
+                  SelectiveGaussianBlur32(FBitmapIceland, ImgViewPage1.Bitmap, Radius, TrackBarDelta.Position);
+
+            end;
+            Stopwatch.Stop;
+          finally
+            ImgViewPage1.EndUpdate;
+          end;
+        end;
+
+      1:
+        begin
+          ImgViewPage2.BeginUpdate;
+          try
+            ImgViewPage2.Bitmap.Assign(FBitmapStoneWeed);
+
+            Pts := Star(130, 150, 90, 5, -0.5 * Pi);
+            Pts2 := Ellipse(350, 250, 100, 60);
+
+            Stopwatch := TStopwatch.StartNew;
+            case RgpBlurType.ItemIndex of
+              1:
+                begin
+                  GaussianBlurRegion[WithGamma](ImgViewPage2.Bitmap, Radius, Pts);
+                  GaussianBlurRegion[WithGamma](ImgViewPage2.Bitmap, Radius, Pts2);
+                end;
+
+              2:
+                if WithGamma then
+                begin
+                  MotionBlurGamma(ImgViewPage2.Bitmap, Radius, TbrBlurAngle.Position, Pts, CbxBidirectional.Checked);
+                  MotionBlurGamma(ImgViewPage2.Bitmap, Radius, TbrBlurAngle.Position, Pts2, CbxBidirectional.Checked);
+                end
+                else
+                begin
+                  MotionBlur(ImgViewPage2.Bitmap, Radius, TbrBlurAngle.Position, Pts, CbxBidirectional.Checked);
+                  MotionBlur(ImgViewPage2.Bitmap, Radius, TbrBlurAngle.Position, Pts2, CbxBidirectional.Checked);
+                end;
+            end;
+            Stopwatch.Stop;
+
+            PolylineFS(ImgViewPage2.Bitmap, Pts, clBlack32, True, 2.5);
+            PolylineFS(ImgViewPage2.Bitmap, Pts2, clBlack32, True, 2.5);
+          finally
+            ImgViewPage2.EndUpdate;
+          end;
+        end;
+
+      2:
+        begin
+          ImgViewPage3.BeginUpdate;
+          try
+            ImgViewPage3.SetupBitmap(True, Color32(clBtnFace));
+
+            Rec := ImgViewPage3.GetBitmapRect;
+            FLayerBitmap.Location := FloatRect(Rec);
+            FLayerBitmap.Bitmap.SetSize(Rec.Width, Rec.Height);
+            FLayerBitmap.Bitmap.Clear(0);
+
+            // Colored squares on layer
+            FLayerBitmap.Bitmap.Draw(300, 40, FBitmapRandBox);
+
+            // Beveled box on background image
+            Rec := Rect(40, 40, 240, 120);
+            DrawFramedBox(ImgViewPage3.Bitmap, Rec, clWhite32, clGray32, Radius div 2);
+
+            // Red rectangle on layer
+            Rec2 := Rect(40, 160, 240, 320);
+            FLayerBitmap.Bitmap.FillRectTS(Rec2, clRed32);
+
+            GR32.InflateRect(Rec2, 20, 20);
+
+            // Ellipse on top of colored squares
+            Pts := Ellipse(395, 175, 60, 100);
+
+            Stopwatch := TStopwatch.StartNew;
+            case RgpBlurType.ItemIndex of
+              1:
+                begin
+                  GaussianBlurBounds[WithGamma](ImgViewPage3.Bitmap, Radius, Rec);
+                  GaussianBlurBounds[WithGamma](FLayerBitmap.Bitmap, Radius, Rec2);
+                  GaussianBlurRegion[WithGamma](FLayerBitmap.Bitmap, Radius, Pts);
+                end;
+
+              2:
+                if WithGamma then
+                begin
+                  MotionBlurGamma(ImgViewPage3.Bitmap, Radius, TbrBlurAngle.Position, Rec, CbxBidirectional.Checked);
+                  MotionBlurGamma(FLayerBitmap.Bitmap, Radius, TbrBlurAngle.Position, Rec2, CbxBidirectional.Checked);
+                  MotionBlurGamma(FLayerBitmap.Bitmap, Radius, TbrBlurAngle.Position, Pts, CbxBidirectional.Checked);
+                end
+                else
+                begin
+                  MotionBlur(ImgViewPage3.Bitmap, Radius, TbrBlurAngle.Position, Rec, CbxBidirectional.Checked);
+                  MotionBlur(FLayerBitmap.Bitmap, Radius, TbrBlurAngle.Position, Rec2, CbxBidirectional.Checked);
+                  MotionBlur(FLayerBitmap.Bitmap, Radius, TbrBlurAngle.Position, Pts, CbxBidirectional.Checked);
+                end;
+            end;
+            Stopwatch.Stop;
+
+            // Outline ellipse
+            PolylineFS(FLayerBitmap.Bitmap, Pts, clTrBlack32, True, 2.5);
+
+            // Outline red rectangle
+            GR32.InflateRect(Rec2, 1, 1);
+            PolylineFS(
+              FLayerBitmap.Bitmap,
+              Rectangle(Rec2),
+              clBlack32,
+              True,
+              0.5);
+
+          finally
+            ImgViewPage3.EndUpdate;
+          end;
+        end;
+    end;
+    SbrMain.SimpleText := Format('  Blur drawing time: %d ms', [Stopwatch.ElapsedMilliseconds]);
+
+  finally
+    FRedrawFlag := False;
+    Screen.Cursor := crDefault;
+  end;
+end;
+
+procedure TFrmBlurs.MnuExitClick(Sender: TObject);
+begin
+  Close;
+end;
+
+procedure TFrmBlurs.RgpBlurTypeClick(Sender: TObject);
+
+  procedure EnableGroup(Parent: TControl; State: boolean);
+  var
+    i: integer;
+  begin
+    Parent.Enabled := State;
+    if (Parent is TWinControl) then
+      for i := 0 to TWinControl(Parent).ControlCount-1 do
+        EnableGroup(TWinControl(Parent).Controls[i], State);
+  end;
+
+begin
+  MnuNone.Checked := (RgpBlurType.ItemIndex = 0);
+  MnuGaussianType.Checked := (RgpBlurType.ItemIndex = 1);
+  MnuMotion.Checked := (RgpBlurType.ItemIndex = 2);
+  MnuSelective.Checked := (RgpBlurType.ItemIndex = 3);
+
+  EnableGroup(PanelRadius, (RgpBlurType.ItemIndex <> 0));
+  EnableGroup(PanelMotion, (RgpBlurType.ItemIndex = 2));
+  EnableGroup(PanelSelective, (RgpBlurType.ItemIndex = 3));
+
+  case RgpBlurType.ItemIndex of
+    1: // The current Gaussian Blur begins introducing overflow artifacts at around radius=200
+      TbrBlurRadius.Max := 200;
+    2: // Motion blur internally limits the radius to 256
+      TbrBlurRadius.Max := 256;
+    3: // Selective blur is very slow, so limit the damage
+      TbrBlurRadius.Max := 20;
+  end;
+
+  Redraw;
+end;
+
+procedure TFrmBlurs.TimerUpdateTimer(Sender: TObject);
+begin
+  TimerUpdate.Enabled := False;
+  Redraw;
+end;
+
+procedure TFrmBlurs.TbrBlurRadiusChange(Sender: TObject);
+begin
+  LblBlurRadius.Caption := Format('Blur &Radius (%d)', [TbrBlurRadius.Position]);
+
+  QueueUpdate;
+end;
+
+procedure TFrmBlurs.TrackBarDeltaChange(Sender: TObject);
+begin
+  LabelDelta.Caption := Format('Delta (%d)', [TrackBarDelta.Position]);
+
+  QueueUpdate;
+end;
+
+procedure TFrmBlurs.TbrBlurAngleChange(Sender: TObject);
+begin
+  LblBlurAngle.Caption := Format('Blur &Angle (%d)', [TbrBlurAngle.Position]);
+
+  QueueUpdate;
+end;
+
+procedure TFrmBlurs.MnuGaussianTypeClick(Sender: TObject);
+begin
+  if Sender = MnuGaussianType then
+    RgpBlurType.ItemIndex := 1
+  else
+  if Sender = MnuMotion then
+    RgpBlurType.ItemIndex := 2
+  else
+  if Sender = MnuSelective then
+    RgpBlurType.ItemIndex := 3
+  else
+    RgpBlurType.ItemIndex := 0
+end;
+
+procedure TFrmBlurs.MnuOpenClick(Sender: TObject);
+begin
+  if OpenDialog.Execute then
+  begin
+    FBitmapIceland.LoadFromFile(OpenDialog.FileName);
+    PageControl.ActivePageIndex := 0;
+    Redraw;
+  end;
+end;
+
+procedure TFrmBlurs.PageControlChange(Sender: TObject);
+begin
+  Redraw;
+end;
+
+procedure TFrmBlurs.QueueUpdate;
+begin
+  TimerUpdate.Enabled := False;
+  TimerUpdate.Enabled := True;
+end;
+
+end.

+ 2 - 0
Externals/Graphics32/Examples/Drawing/Blurs/Media.rc

@@ -0,0 +1,2 @@
+ICELAND RCDATA "../../Media/iceland.jpg"
+STONEWEED RCDATA "../../Media/stoneweed.jpg"

+ 13 - 0
Externals/Graphics32/Examples/Drawing/Clipper/ClipperDemo.dpr

@@ -0,0 +1,13 @@
+program ClipperDemo;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFrmClipper, FrmClipper);
+  Application.Run;
+end.

+ 148 - 0
Externals/Graphics32/Examples/Drawing/Clipper/ClipperDemo.dproj

@@ -0,0 +1,148 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>ClipperDemo.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{a49122ea-b95a-44b3-9eb7-607f276022df}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">ClipperDemo</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>ClipperDemo</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">ClipperDemo.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

+ 116 - 0
Externals/Graphics32/Examples/Drawing/Clipper/MainUnit.dfm

@@ -0,0 +1,116 @@
+object FrmClipper: TFrmClipper
+  Left = 280
+  Top = 166
+  Caption = 'Clipper'
+  ClientHeight = 470
+  ClientWidth = 710
+  Color = clBtnFace
+  Font.Charset = ANSI_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -12
+  Font.Name = 'Arial'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCreate = FormCreate
+  OnKeyDown = FormKeyDown
+  PixelsPerInch = 96
+  TextHeight = 15
+  object PnlControl: TPanel
+    Left = 0
+    Top = 0
+    Width = 173
+    Height = 470
+    Align = alLeft
+    TabOrder = 0
+    ExplicitHeight = 508
+    object BtnExit: TButton
+      Left = 16
+      Top = 420
+      Width = 138
+      Height = 25
+      Cancel = True
+      Caption = 'Exit'
+      TabOrder = 5
+      OnClick = BtnExitClick
+    end
+    object rgClipping: TRadioGroup
+      Left = 16
+      Top = 26
+      Width = 138
+      Height = 127
+      Caption = 'Clipping Op'
+      ItemIndex = 1
+      Items.Strings = (
+        '&Intersection'
+        '&Union'
+        '&Difference'
+        '&XOR')
+      TabOrder = 0
+    end
+    object BtnClear: TButton
+      Left = 16
+      Top = 384
+      Width = 138
+      Height = 25
+      Caption = '&Clear'
+      TabOrder = 4
+      OnClick = BtnClearClick
+    end
+    object RgpObject: TRadioGroup
+      Left = 16
+      Top = 176
+      Width = 138
+      Height = 98
+      Caption = 'Shape'
+      ItemIndex = 0
+      Items.Strings = (
+        '&Star'
+        '&Ellipse'
+        '&Rectangle')
+      TabOrder = 1
+    end
+    object BtnInflate: TButton
+      Left = 16
+      Top = 296
+      Width = 138
+      Height = 25
+      Caption = 'In&flate'
+      TabOrder = 2
+      OnClick = BtnInflateClick
+    end
+    object BtnDeflate: TButton
+      Left = 16
+      Top = 330
+      Width = 138
+      Height = 25
+      Caption = 'Defla&te'
+      TabOrder = 3
+      OnClick = BtnDeflateClick
+    end
+  end
+  object ImgView32: TImgView32
+    Left = 173
+    Top = 0
+    Width = 537
+    Height = 470
+    Align = alClient
+    AutoSize = True
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baCenter
+    Scale = 1.000000000000000000
+    ScaleMode = smScale
+    ScrollBars.ShowHandleGrip = True
+    ScrollBars.Style = rbsDefault
+    ScrollBars.Size = 16
+    ScrollBars.Visibility = svHidden
+    SizeGrip = sgAlways
+    OverSize = 0
+    TabOrder = 1
+    OnMouseDown = ImgView32MouseDown
+    OnMouseLeave = ImgView32MouseLeave
+    OnMouseMove = ImgView32MouseMove
+    ExplicitLeft = 169
+    ExplicitWidth = 665
+    ExplicitHeight = 508
+  end
+end

+ 219 - 0
Externals/Graphics32/Examples/Drawing/Clipper/MainUnit.pas

@@ -0,0 +1,219 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is GR32_Clipper Example
+ *
+ * The Initial Developer of the Original Code is
+ * Angus Johnson
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFNDEF FPC}Windows, {$ELSE} LCLIntf, LCLType, {$ENDIF} SysUtils, Classes,
+  Types, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Math,
+  GR32, GR32_Image, GR32_Polygons, GR32_Layers, GR32_Geometry,
+  GR32_Math, GR32_VectorUtils, GR32_Clipper;
+
+type
+  TFrmClipper = class(TForm)
+    BtnClear: TButton;
+    BtnExit: TButton;
+    ImgView32: TImgView32;
+    PnlControl: TPanel;
+    rgClipping: TRadioGroup;
+    RgpObject: TRadioGroup;
+    BtnInflate: TButton;
+    BtnDeflate: TButton;
+    procedure FormCreate(Sender: TObject);
+    procedure BtnExitClick(Sender: TObject);
+    procedure ImgView32MouseMove(Sender: TObject; Shift: TShiftState; X,
+      Y: Integer; Layer: TCustomLayer);
+    procedure ImgView32MouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+    procedure BtnClearClick(Sender: TObject);
+    procedure ImgView32MouseLeave(Sender: TObject);
+    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+    procedure BtnInflateClick(Sender: TObject);
+    procedure BtnDeflateClick(Sender: TObject);
+  private
+    Polys: TArrayOfArrayOfFloatPoint;
+    OutlinePolygon: TArrayOfFloatPoint;
+    procedure AddPolygon(const Pts: TArrayOfFloatPoint);
+    function MakeRectangle(const NewPoint: TPoint): TArrayOfFloatPoint;
+    function MakeEllipse(const NewPoint: TPoint): TArrayOfFloatPoint;
+    function MakeStar(const NewPoint: TPoint): TArrayOfFloatPoint;
+    procedure DrawPolygons;
+  end;
+
+var
+  FrmClipper: TFrmClipper;
+
+implementation
+
+{$R *.dfm}
+
+procedure DrawStippled(Bitmap: TBitmap32;
+  const Afp: TArrayOfFloatPoint;
+  StippleColors: array of TColor32; StippleStep: TFloat);
+var
+  i: Integer;
+begin
+  if Afp = nil then Exit;
+  Bitmap.StippleStep := StippleStep;
+  Bitmap.SetStipple(StippleColors);
+  Bitmap.MoveToF(Afp[0].X, Afp[0].Y);
+  for i := 1 to High(Afp) do
+    Bitmap.LineToFSP(Afp[i].X, Afp[i].Y);
+  Bitmap.LineToFSP(Afp[0].X, Afp[0].Y);
+end;
+
+
+{ TFrmClipper methods }
+
+procedure TFrmClipper.FormCreate(Sender: TObject);
+begin
+  ImgView32.SetupBitmap(true);
+  AddPolygon(MakeStar(GR32.Point(125, 150)));
+  ImgView32.ScrollToCenter(0, 0);
+end;
+
+procedure TFrmClipper.FormKeyDown(Sender: TObject; var Key: Word;
+  Shift: TShiftState);
+begin
+  if Key = 27 then
+    Exit;
+end;
+
+procedure TFrmClipper.AddPolygon(const Pts: TArrayOfFloatPoint);
+var
+  ct: TClipType;
+  Clipper: TClipper32;
+begin
+  Clipper := TClipper32.Create;
+  try
+    //add multiple contours of existing polygons as subject polygons ...
+    Clipper.AddPaths(Polys, ptSubject);
+    //add the single contour of the new polygon as the clipping polygon ...
+    Clipper.AddPath(Pts, ptClip);
+
+    //do the clipping operation (result => Polys) ...
+    case rgClipping.ItemIndex of
+      0: ct := ctIntersection;
+      1:  ct := ctUnion;
+      2:  ct := ctDifference;
+      else  ct := ctXor;
+    end;
+    Clipper.Execute(ct, frNonZero, Polys);
+  finally
+    Clipper.Free;
+  end;
+  DrawPolygons;
+end;
+
+function TFrmClipper.MakeRectangle(const NewPoint: TPoint): TArrayOfFloatPoint;
+begin
+  SetLength(Result, 4);
+  Result[0] := FloatPoint(NewPoint.X - 50, NewPoint.Y - 30);
+  Result[1] := FloatPoint(NewPoint.X + 50, NewPoint.Y - 30);
+  Result[2] := FloatPoint(NewPoint.X + 50, NewPoint.Y + 30);
+  Result[3] := FloatPoint(NewPoint.X - 50, NewPoint.Y + 30);
+end;
+
+function TFrmClipper.MakeEllipse(const NewPoint: TPoint): TArrayOfFloatPoint;
+begin
+  Result := Ellipse(FloatPoint(NewPoint), FloatPoint(60,40));
+end;
+
+function TFrmClipper.MakeStar(const NewPoint: TPoint): TArrayOfFloatPoint;
+begin
+  Result := Star(FloatPoint(NewPoint), 40.0, 60.0, 7);
+end;
+
+procedure TFrmClipper.DrawPolygons;
+begin
+  ImgView32.Bitmap.FillRectS(ImgView32.Bitmap.BoundsRect, clWhite32);
+  PolyPolyLineFS(ImgView32.Bitmap, Polys, clRed32, True, 2);
+  PolyPolygonFS(ImgView32.Bitmap, Polys, $40FF0000, pfWinding);
+  DrawStippled(ImgView32.Bitmap,
+    OutlinePolygon, [clBlue32, clBlue32, $000000FF], 0.35);
+end;
+
+procedure TFrmClipper.ImgView32MouseDown(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer;
+  Layer: TCustomLayer);
+begin
+  AddPolygon(OutlinePolygon);
+end;
+
+procedure TFrmClipper.ImgView32MouseMove(Sender: TObject;
+  Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+var
+  NewPt: TPoint;
+begin
+  NewPt := ImgView32.ControlToBitmap(GR32.Point(X, Y));
+  case RgpObject.ItemIndex of
+    0: OutlinePolygon := MakeStar(NewPt);
+    1: OutlinePolygon := MakeEllipse(NewPt);
+    else OutlinePolygon := MakeRectangle(NewPt);
+  end;
+  DrawPolygons;
+end;
+
+procedure TFrmClipper.ImgView32MouseLeave(Sender: TObject);
+begin
+  OutlinePolygon := nil;
+  DrawPolygons;
+end;
+
+procedure TFrmClipper.BtnExitClick(Sender: TObject);
+begin
+  Close;
+end;
+
+procedure TFrmClipper.BtnClearClick(Sender: TObject);
+begin
+  Polys := nil;
+  DrawPolygons;
+end;
+
+procedure TFrmClipper.BtnInflateClick(Sender: TObject);
+begin
+  Polys := InflatePaths(Polys, 10, jtRound, etPolygon);
+  DrawPolygons;
+end;
+
+procedure TFrmClipper.BtnDeflateClick(Sender: TObject);
+begin
+  Polys := InflatePaths(Polys, -10, jtRound, etPolygon);
+  DrawPolygons;
+end;
+
+end.

+ 1 - 0
Externals/Graphics32/Examples/Drawing/Clipper/Media.rc

@@ -0,0 +1 @@
+MainIcon ICON "../../Media/GR32.ico"

+ 14 - 0
Externals/Graphics32/Examples/Drawing/CubicSpline/CubicSpline.dpr

@@ -0,0 +1,14 @@
+program CubicSpline;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFormBezier, FormBezier);
+  Application.Run;
+end.
+

+ 167 - 0
Externals/Graphics32/Examples/Drawing/CubicSpline/CubicSpline.dproj

@@ -0,0 +1,167 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>CubicSpline.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{6d801fac-172c-4b7c-8a45-04d0f9fa7f2a}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">CubicSpline</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>CubicSpline</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">CubicSpline.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 32 - 0
Externals/Graphics32/Examples/Drawing/CubicSpline/MainUnit.dfm

@@ -0,0 +1,32 @@
+object FormBezier: TFormBezier
+  Left = 0
+  Top = 0
+  Caption = 'Bezier Curves'
+  ClientHeight = 480
+  ClientWidth = 640
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCreate = FormCreate
+  OnDestroy = FormDestroy
+  OnKeyDown = FormKeyDown
+  PixelsPerInch = 96
+  TextHeight = 13
+  object PaintBox32: TPaintBox32
+    Left = 0
+    Top = 0
+    Width = 640
+    Height = 480
+    Align = alClient
+    TabOrder = 0
+    OnDblClick = PaintBox32DblClick
+    OnMouseDown = PaintBox32MouseDown
+    OnMouseMove = PaintBox32MouseMove
+    OnMouseUp = PaintBox32MouseUp
+    OnPaintBuffer = PaintBox32PaintBuffer
+  end
+end

+ 273 - 0
Externals/Graphics32/Examples/Drawing/CubicSpline/MainUnit.pas

@@ -0,0 +1,273 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is Vectorial Polygon Rasterizer for Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Christian-W. Budde
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFDEF FPC}LCLIntf, {$ELSE}Windows, {$ENDIF} SysUtils, Classes, Graphics,
+  Controls, Forms, Dialogs, GR32, GR32_Image, GR32_Polygons, GR32_Paths;
+
+type
+  TFormBezier = class(TForm)
+    PaintBox32: TPaintBox32;
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+    procedure PaintBox32PaintBuffer(Sender: TObject);
+    procedure PaintBox32DblClick(Sender: TObject);
+    procedure PaintBox32MouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure PaintBox32MouseUp(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure PaintBox32MouseMove(Sender: TObject; Shift: TShiftState; X,
+      Y: Integer);
+    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+  private
+    FRenderer: TPolygonRenderer32VPR;
+    FCurrentIndex: Integer;
+    FVertices: TArrayOfFloatPoint;
+    procedure RandomizeVertices;
+  end;
+
+var
+  FormBezier: TFormBezier;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Math,
+  Types,
+  GR32_Math,
+  GR32_LowLevel,
+  GR32_VectorUtils;
+
+{ TFormBezier }
+
+procedure TFormBezier.FormCreate(Sender: TObject);
+begin
+  FRenderer := TPolygonRenderer32VPR.Create(PaintBox32.Buffer);
+
+  SetLength(FVertices, 6);
+  RandomizeVertices;
+
+  FCurrentIndex := -1;
+end;
+
+procedure TFormBezier.FormDestroy(Sender: TObject);
+begin
+  FRenderer.Free;
+end;
+
+procedure TFormBezier.FormKeyDown(Sender: TObject; var Key: Word;
+  Shift: TShiftState);
+begin
+  case Key of
+    27: Close;
+    13:
+      begin
+        RandomizeVertices;
+        PaintBox32.Invalidate;
+      end;
+    187:
+      begin
+        SetLength(FVertices, Length(FVertices) + 1);
+        with PaintBox32 do
+          FVertices[Length(FVertices) - 1] := FloatPoint(Random * Width,
+            Random * Height);
+        PaintBox32.Invalidate;
+      end;
+    189:
+      if Length(FVertices) > 5 then
+      begin
+        SetLength(FVertices, Length(FVertices) - 1);
+        PaintBox32.Invalidate;
+      end;
+  end;
+
+end;
+
+function CubicInterpolation(const Fractional: TFloat;
+  const Data0, Data1, Data2, Data3: TFloat): TFloat;
+begin
+  Result := Data1 + 0.5 * Fractional * (Data2 - Data0 + Fractional *
+    (4 * Data2 + 2 * Data0 - 5 * Data1 - Data3 + Fractional *
+    (3 * (Data1 - Data2) - Data0 + Data3)));
+end;
+
+procedure TFormBezier.RandomizeVertices;
+var
+  Index: Integer;
+begin
+  with PaintBox32 do
+    for Index := 0 to High(FVertices) do
+      FVertices[Index] := FloatPoint(Random * Width, Random * Height);
+end;
+
+procedure TFormBezier.PaintBox32DblClick(Sender: TObject);
+begin
+  RandomizeVertices;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFormBezier.PaintBox32MouseDown(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+var
+  Index: Integer;
+  Dist, MinDist: TFloat;
+  MinDistIndex: Integer;
+begin
+  FCurrentIndex := -1;
+  for Index := 0 to Length(FVertices) - 1 do
+    if Sqr(FVertices[Index].X - X) + Sqr(FVertices[Index].Y - Y)  < 25 then
+    begin
+      if (Length(FVertices) > 5) and (Button = mbRight) then
+      begin
+        if Index < Length(FVertices) - 1 then
+          Move(FVertices[Index + 1], FVertices[Index],
+            (Length(FVertices) - Index - 1) * SizeOf(TFloatPoint));
+        SetLength(FVertices, Length(FVertices) - 1);
+        PaintBox32.Invalidate;
+      end
+      else
+        FCurrentIndex := Index;
+      Exit;
+    end;
+
+  if Button = mbLeft then
+  begin
+    MinDistIndex := 0;
+    MinDist := Sqr(X - FVertices[0].X) + Sqr(Y - FVertices[0].Y);
+    for Index := 1 to High(FVertices) do
+    begin
+      Dist := Sqr(X - FVertices[Index].X) + Sqr(Y - FVertices[Index].Y);
+      if Dist < MinDist then
+      begin
+        MinDistIndex := Index;
+        MinDist := Dist;
+      end;
+    end;
+
+    SetLength(FVertices, Length(FVertices) + 1);
+    Move(FVertices[MinDistIndex], FVertices[MinDistIndex + 1],
+      (Length(FVertices) - MinDistIndex) * SizeOf(TFloatPoint));
+    FCurrentIndex := MinDistIndex;
+    FVertices[FCurrentIndex] := FloatPoint(X, Y);
+    PaintBox32.Invalidate;
+  end;
+end;
+
+procedure TFormBezier.PaintBox32MouseMove(Sender: TObject; Shift: TShiftState;
+  X, Y: Integer);
+begin
+  if FCurrentIndex >= 0 then
+  begin
+    FVertices[FCurrentIndex] := FloatPoint(X, Y);
+    PaintBox32.Invalidate;
+  end;
+end;
+
+procedure TFormBezier.PaintBox32MouseUp(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+begin
+  if FCurrentIndex >= 0 then
+  with PaintBox32 do
+    begin
+      FVertices[FCurrentIndex].X := EnsureRange(FVertices[FCurrentIndex].X,
+        0, Width);
+      FVertices[FCurrentIndex].Y := EnsureRange(FVertices[FCurrentIndex].Y,
+        0, Height);
+    end;
+
+  FCurrentIndex := -1;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFormBezier.PaintBox32PaintBuffer(Sender: TObject);
+var
+  Index: Integer;
+  Val: Double;
+  Fractional: Double;
+  Indices: array [0..3] of Integer;
+  PolyCount: Integer;
+  Outline: TArrayOfArrayOfFloatPoint;
+const
+  CVertexCountStep = 64;
+begin
+  PaintBox32.Buffer.Clear($FFFFFFFF);
+
+  Outline := BuildPolyPolyLine(PolyPolygon(FVertices), True, 2);
+
+  PolyCount := Length(Outline);
+  SetLength(Outline, PolyCount + Length(FVertices));
+  for Index := 0 to Length(FVertices) - 1 do
+    Outline[PolyCount + Index] := Circle(FVertices[Index].X, FVertices[Index].Y, 5, 32);
+
+  FRenderer.Color := $80000080;
+  FRenderer.PolyPolygonFS(Outline);
+
+  SetLength(Outline, 1, CVertexCountStep);
+  Outline[0, 0] := FVertices[0];
+  Index := 0;
+  Val := 0;
+  while Val < Length(FVertices) do
+  begin
+    Indices[0] := (Length(FVertices) + Trunc(Val) - 2 + 1) mod Length(FVertices);
+    Indices[1] := (Indices[0] + 1) mod Length(FVertices);
+    Indices[2] := (Indices[1] + 1) mod Length(FVertices);
+    Indices[3] := (Indices[2] + 1) mod Length(FVertices);
+
+    Fractional := Frac(Val);
+
+    Inc(Index);
+    if Index = Length(Outline[0]) then
+      SetLength(Outline[0], Length(Outline[0]) + CVertexCountStep);
+
+    Outline[0, Index] := FloatPoint(
+      CubicInterpolation(Fractional, FVertices[Indices[0]].X,
+        FVertices[Indices[1]].X, FVertices[Indices[2]].X,
+        FVertices[Indices[3]].X),
+      CubicInterpolation(Fractional, FVertices[Indices[0]].Y,
+        FVertices[Indices[1]].Y, FVertices[Indices[2]].Y,
+        FVertices[Indices[3]].Y));
+    Val := Val + 0.03;
+  end;
+  SetLength(Outline[0], Index + 1);
+  FRenderer.Color := $FF000000;
+  FRenderer.PolyPolygonFS(BuildPolyPolyline(Outline, True, 2));
+end;
+
+end.

+ 1 - 0
Externals/Graphics32/Examples/Drawing/CubicSpline/Media.rc

@@ -0,0 +1 @@
+MainIcon ICON "../../Media/GR32.ico"

+ 13 - 0
Externals/Graphics32/Examples/Drawing/Curves/Curves.dpr

@@ -0,0 +1,13 @@
+program Curves;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TMainForm, MainForm);
+  Application.Run;
+end.

+ 167 - 0
Externals/Graphics32/Examples/Drawing/Curves/Curves.dproj

@@ -0,0 +1,167 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>Curves.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{98b9209c-3476-4d4a-b4a6-9d0668bb66e4}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">Curves</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>Curves</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">Curves.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 49 - 0
Externals/Graphics32/Examples/Drawing/Curves/MainUnit.dfm

@@ -0,0 +1,49 @@
+object MainForm: TMainForm
+  Left = 833
+  Top = 165
+  Caption = 'Curves Example'
+  ClientHeight = 560
+  ClientWidth = 527
+  Color = clBtnFace
+  ParentFont = True
+  OnShow = BtnDrawCurveClick
+  TextHeight = 15
+  object Paintbox: TPaintBox32
+    Left = 0
+    Top = 0
+    Width = 527
+    Height = 519
+    Align = alClient
+    TabOrder = 0
+    OnClick = PaintboxClick
+    OnPaintBuffer = PaintboxPaintBuffer
+  end
+  object Panel1: TPanel
+    Left = 0
+    Top = 519
+    Width = 527
+    Height = 41
+    Align = alBottom
+    BevelOuter = bvNone
+    ShowCaption = False
+    TabOrder = 1
+    object BtnDrawCurve: TButton
+      Left = 8
+      Top = 7
+      Width = 97
+      Height = 25
+      Caption = 'Draw Curve'
+      TabOrder = 0
+      OnClick = BtnDrawCurveClick
+    end
+    object CbxUpdate: TCheckBox
+      Left = 119
+      Top = 11
+      Width = 88
+      Height = 17
+      Caption = 'Timer'
+      TabOrder = 1
+      OnClick = CbxUpdateClick
+    end
+  end
+end

+ 390 - 0
Externals/Graphics32/Examples/Drawing/Curves/MainUnit.pas

@@ -0,0 +1,390 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is Curves Example (based on VPR example)
+ *
+ * The Initial Developer of the Original Code is
+ * Mattias Andersson <[email protected]>
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFDEF FPC} LCLIntf, LResources, Buttons, {$ENDIF}
+  Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,
+  ExtCtrls,
+  GR32,
+  GR32_Image,
+  GR32_Polygons,
+  GR32_Transforms,
+  GR32_Paths,
+  GR32_Brushes;
+
+type
+  // Draws a single dot at each vertex
+  TDotBrush = class(TCustomBrush)
+  strict private
+    FColor: TColor32;
+  private
+    procedure SetColor(const Value: TColor32);
+  protected
+    procedure RenderPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
+      const ClipRect: TFloatRect; Transformation: TTransformation); override;
+  public
+    constructor Create(BrushCollection: TBrushCollection); override;
+
+    property Color: TColor32 read FColor write SetColor;
+  end;
+
+type
+  // Draws a circle, using the nested brushes, at each vertex
+  TCircleBrush = class(TNestedBrush)
+  strict private
+    FRadius: TFloat;
+  private
+    procedure SetRadius(const Value: TFloat);
+  protected
+  public
+    constructor Create(BrushCollection: TBrushCollection); override;
+
+    procedure PolyPolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
+      const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean); override;
+    procedure PolyPolygonMixedFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
+      const ClipRect: TFloatRect; Transformation: TTransformation; Closed: TBooleanArray); override;
+
+    property Radius: TFloat read FRadius write SetRadius;
+  end;
+
+type
+  TMainForm = class(TForm)
+    Paintbox: TPaintBox32;
+    Panel1: TPanel;
+    BtnDrawCurve: TButton;
+    CbxUpdate: TCheckBox;
+    procedure BtnDrawCurveClick(Sender: TObject);
+    procedure CbxUpdateClick(Sender: TObject);
+    procedure ApplicationIdleHandler(Sender: TObject; var Done: Boolean);
+    procedure PaintboxClick(Sender: TObject);
+    procedure PaintboxPaintBuffer(Sender: TObject);
+  private
+    FCanvas32: TCanvas32;
+    FCurveBrushes: TNestedBrush;
+    FPointsBrushes: TNestedBrush;
+
+    FBrushFill: TSolidBrush;
+    FBrushDash: TDashedBrush;
+    FBrushDot: TDotBrush;
+    FBrushCircle: TCircleBrush;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+  end;
+
+var
+  MainForm: TMainForm;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Math,
+  Types,
+  GR32_Math,
+  GR32_Geometry,
+  GR32_VectorUtils,
+  GR32_Resamplers,
+  GR32_LowLevel;
+
+constructor TDotBrush.Create(BrushCollection: TBrushCollection);
+begin
+  inherited;
+  FColor := clWhite32;
+end;
+
+procedure TDotBrush.RenderPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
+  const ClipRect: TFloatRect; Transformation: TTransformation);
+var
+  i, j: integer;
+  Bitmap: TCustomBitmap32;
+begin
+  Bitmap := (Renderer as TPolygonRenderer32).Bitmap;
+  for i := 0 to High(Points) do
+    for j := 0 to High(Points[i]) do
+      Bitmap.PixelFS[Points[i, j].X, Points[i, j].Y] := FColor;
+end;
+
+procedure TDotBrush.SetColor(const Value: TColor32);
+begin
+  if (FColor = Value) then
+    exit;
+  FColor := Value;
+  Changed;
+end;
+
+constructor TCircleBrush.Create(BrushCollection: TBrushCollection);
+begin
+  inherited;
+  FRadius := 2.0;
+end;
+
+procedure TCircleBrush.PolyPolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
+  const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean);
+var
+  CirclePoints: TArrayOfArrayOfFloatPoint;
+  Center, LastCenter, Delta: TFloatPoint;
+  i, j, k: integer;
+begin
+  LastCenter := FloatPoint(0, 0);
+  SetLength(CirclePoints, 1);
+  CirclePoints[0] := Circle(LastCenter, FRadius);
+
+  for i := 0 to High(Points) do
+    for j := 0 to High(Points[i]) do
+    begin
+      Center := Points[i, j];
+
+      Delta := Center - LastCenter;
+      LastCenter := Center;
+
+      // Translate circle to new center in-place
+      for k := 0 to High(CirclePoints[0]) do
+        CirclePoints[0, k] := CirclePoints[0, k] + Delta;
+
+      inherited PolyPolygonFS(Renderer, CirclePoints, ClipRect, Transformation, True);
+
+    end;
+end;
+
+procedure TCircleBrush.PolyPolygonMixedFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
+  const ClipRect: TFloatRect; Transformation: TTransformation; Closed: TBooleanArray);
+begin
+  PolyPolygonFS(Renderer, Points, ClipRect, Transformation, True);
+end;
+
+procedure TCircleBrush.SetRadius(const Value: TFloat);
+begin
+  if (FRadius = Value) then
+    exit;
+  FRadius := Value;
+  Changed;
+end;
+
+function MakeCurve(const Points: TArrayOfFloatPoint; Kernel: TCustomKernel;
+  Closed: Boolean): TArrayOfFloatPoint;
+const
+  TOLERANCE: TFloat = 20.0;
+  THRESHOLD: TFloat = 0.5;
+var
+  I, H, R: Integer;
+  Filter: TFilterMethod;
+  WrapProc: TWrapProc;
+
+  procedure AddPoint(const P: TFloatPoint);
+  var
+    L: Integer;
+  begin
+    L := Length(Result);
+    SetLength(Result, L + 1);
+    Result[L] := P;
+  end;
+
+  function GetPoint(I: Integer; t: TFloat = 0.0): TFloatPoint;
+  var
+    f, Index: Integer;
+    W: TFloat;
+  begin
+    Result.X := 0; Result.Y := 0;
+    for f := -R to R do
+    begin
+      Index := WrapProc(I - f, H);
+      W := Filter(f + t);
+      Result.X := Result.X + W * Points[Index].X;
+      Result.Y := Result.Y + W * Points[Index].Y;
+    end;
+  end;
+
+  procedure Recurse(I: Integer; const P1, P2: TFloatPoint; const t1, t2: TFloat);
+  var
+    Temp: TFloat;
+    P: TFloatPoint;
+  begin
+    AddPoint(P1);
+    Temp := (t1 + t2) * 0.5;
+    P := GetPoint(I, Temp);
+
+    if (Abs(CrossProduct(FloatPoint(P1.X - P.X, P1.Y - P.Y),
+      FloatPoint(P.X - P2.X, P.Y - P2.Y))) > TOLERANCE) or (t2 - t1 >= THRESHOLD) then
+    begin
+      Recurse(I, P1, P, t1, Temp);
+      Recurse(I, P, P2, Temp, t2);
+    end else
+      AddPoint(P);
+  end;
+
+const
+  WRAP_PROC: array[Boolean] of TWrapProc = (Clamp, Wrap);
+begin
+  SetLength(Result, 0);
+
+  WrapProc := Wrap_PROC[Closed];
+  Filter := Kernel.Filter;
+  R := Ceil(Kernel.GetWidth);
+  H := High(Points);
+
+  for I := 0 to H - 1 do
+    Recurse(I, GetPoint(I), GetPoint(I + 1), 0, 1);
+
+  if Closed then
+    Recurse(H, GetPoint(H), GetPoint(0), 0, 1)
+  else
+    AddPoint(GetPoint(H));
+end;
+
+constructor TMainForm.Create(AOwner: TComponent);
+var
+  BrushCircleFill: TSolidBrush;
+  BrushCircleStroke: TStrokeBrush;
+begin
+  inherited;
+
+  FCanvas32 := TCanvas32.Create(Paintbox.Buffer);
+
+  FCurveBrushes := TNestedBrush(FCanvas32.Brushes.Add(TNestedBrush));
+  FPointsBrushes := TNestedBrush(FCanvas32.Brushes.Add(TNestedBrush));
+
+
+  FBrushFill := TSolidBrush(FCurveBrushes.Brushes.Add(TSolidBrush));
+  FBrushFill.FillColor := clIndianRed32;
+  FBrushFill.FillMode := pfEvenOdd;
+
+  FBrushDash := TDashedBrush(FCurveBrushes.Brushes.Add(TDashedBrush));
+  FBrushDash.FillColor := clWhite32;
+  FBrushDash.StrokeWidth := 6;
+  FBrushDash.DashArray := [10, 5];
+  FBrushDash.Visible := False;
+
+  FBrushDot := TDotBrush(FCurveBrushes.Brushes.Add(TDotBrush));
+  FBrushDot.Color := clLime32;
+
+
+  FBrushCircle := TCircleBrush(FPointsBrushes.Brushes.Add(TCircleBrush));
+  FBrushCircle.Radius := 4;
+
+  BrushCircleFill := TSolidBrush(FBrushCircle.Brushes.Add(TSolidBrush));
+  BrushCircleFill.FillColor := clBlue32;
+
+  BrushCircleStroke := TStrokeBrush(FBrushCircle.Brushes.Add(TStrokeBrush));
+  BrushCircleStroke.FillColor := clWhite32;
+  BrushCircleStroke.StrokeWidth := 1.5;
+
+{$ifndef FPC}
+  Paintbox.Margins.SetBounds(8,8,8,8);
+  Paintbox.AlignWithMargins := True;
+{$endif}
+end;
+
+destructor TMainForm.Destroy;
+begin
+  FCanvas32.Free;
+  inherited;
+end;
+
+procedure TMainForm.PaintboxClick(Sender: TObject);
+begin
+  FBrushDash.Visible := not FBrushDash.Visible;
+  Paintbox.ForceFullInvalidate;
+end;
+
+procedure TMainForm.BtnDrawCurveClick(Sender: TObject);
+begin
+  Paintbox.ForceFullInvalidate;
+end;
+
+procedure TMainForm.PaintboxPaintBuffer(Sender: TObject);
+var
+  Points, Curve: TArrayOfFloatPoint;
+  I: Integer;
+  K: TCustomKernel;
+begin
+  Paintbox.Buffer.Clear($FF333333);
+  SetLength(Points, 8);
+
+  // Create a set of random data points
+  for I := 0 to High(Points) do
+    Points[I] := FloatPoint(Random(Paintbox.Buffer.Width), Random(Paintbox.Buffer.Height));
+
+  // Create interpolation kernel
+  // We previously used TGaussianKernel here but after that kernel was fixed
+  // it no longer gives us the curve we would like; A curve that intersects
+  // the control points.
+  K := THammingKernel.Create;
+  try
+    // Subdivide recursively and interpolate
+    Curve := MakeCurve(Points, K, True);
+  finally
+    K.Free;
+  end;
+
+  // Draw result polygon
+  FCanvas32.BeginUpdate;
+  try
+    FCurveBrushes.Visible := True;
+    FPointsBrushes.Visible := False;
+
+    FCanvas32.Polygon(Curve);
+  finally
+    FCanvas32.EndUpdate;
+  end;
+
+  // Draw control points
+  FCanvas32.BeginUpdate;
+  try
+    FCurveBrushes.Visible := False;
+    FPointsBrushes.Visible := True;
+
+    FCanvas32.Polygon(Points);
+  finally
+    FCanvas32.EndUpdate;
+  end;
+end;
+
+procedure TMainForm.ApplicationIdleHandler(Sender: TObject; var Done: Boolean);
+begin
+  Paintbox.ForceFullInvalidate;
+end;
+
+procedure TMainForm.CbxUpdateClick(Sender: TObject);
+begin
+  if CbxUpdate.Checked then
+    Application.OnIdle := ApplicationIdleHandler
+  else
+    Application.OnIdle := nil;
+end;
+
+end.

+ 1 - 0
Externals/Graphics32/Examples/Drawing/Curves/Media.rc

@@ -0,0 +1 @@
+MainIcon ICON "../../Media/GR32.ico"

+ 13 - 0
Externals/Graphics32/Examples/Drawing/GammaBlur/GammaBlur.dpr

@@ -0,0 +1,13 @@
+program GammaBlur;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas' {FormGammaBlur};
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFormGammaBlur, FormGammaBlur);
+  Application.Run;
+end.

+ 169 - 0
Externals/Graphics32/Examples/Drawing/GammaBlur/GammaBlur.dproj

@@ -0,0 +1,169 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>GammaBlur.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{e76047c7-32d7-426d-bac0-e8ba53e24c47}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">GammaBlur</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>GammaBlur</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas">
+            <Form>FormGammaBlur</Form>
+        </DCCReference>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">GammaBlur.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 165 - 0
Externals/Graphics32/Examples/Drawing/GammaBlur/MainUnit.dfm

@@ -0,0 +1,165 @@
+object FormGammaBlur: TFormGammaBlur
+  Left = 100
+  Top = 189
+  BorderStyle = bsDialog
+  Caption = 'GammaBlur'
+  ClientHeight = 338
+  ClientWidth = 263
+  Color = clBtnFace
+  ParentFont = True
+  Position = poScreenCenter
+  OnCreate = FormCreate
+  DesignSize = (
+    263
+    338)
+  TextHeight = 15
+  object LabelIncorrect: TLabel
+    Left = 8
+    Top = 32
+    Width = 193
+    Height = 15
+    Caption = 'Incorrect (without gamma handling)'
+  end
+  object LabelCorrect: TLabel
+    Left = 8
+    Top = 135
+    Width = 167
+    Height = 15
+    Caption = 'Correct (with gamma handling)'
+  end
+  object LabelGamma: TLabel
+    Left = 8
+    Top = 231
+    Width = 45
+    Height = 15
+    Caption = 'Gamma:'
+    ParentShowHint = False
+    ShowHint = True
+  end
+  object LabelGammaValue: TLabel
+    Left = 215
+    Top = 230
+    Width = 3
+    Height = 15
+    Anchors = [akTop, akRight]
+  end
+  object LabelBlur: TLabel
+    Left = 8
+    Top = 284
+    Width = 68
+    Height = 15
+    Caption = 'Blur Radius:'
+  end
+  object LabelBlurValue: TLabel
+    Left = 215
+    Top = 283
+    Width = 3
+    Height = 15
+    Anchors = [akTop, akRight]
+  end
+  object PaintBoxIncorrect: TPaintBox32
+    Left = 8
+    Top = 53
+    Width = 247
+    Height = 68
+    Anchors = [akLeft, akTop, akRight]
+    TabOrder = 0
+    OnPaintBuffer = PaintBoxIncorrectPaintBuffer
+    OnResize = PaintBoxResize
+  end
+  object PaintBoxCorrect: TPaintBox32
+    Left = 8
+    Top = 156
+    Width = 247
+    Height = 68
+    Anchors = [akLeft, akTop, akRight]
+    TabOrder = 1
+    OnPaintBuffer = PaintBoxCorrectPaintBuffer
+    OnResize = PaintBoxResize
+  end
+  object GaugeBarGamma: TGaugeBar
+    Left = 82
+    Top = 230
+    Width = 127
+    Height = 16
+    Anchors = [akLeft, akTop, akRight]
+    Backgnd = bgPattern
+    LargeChange = 100
+    Max = 3000
+    Min = 300
+    ShowHandleGrip = True
+    Position = 2200
+    OnChange = GaugeBarGammaChange
+  end
+  object GaugeBarBlurRadius: TGaugeBar
+    Left = 82
+    Top = 283
+    Width = 127
+    Height = 16
+    Anchors = [akLeft, akTop, akRight]
+    Backgnd = bgPattern
+    LargeChange = 100
+    Max = 200
+    Min = 1
+    ShowHandleGrip = True
+    Position = 50
+    OnChange = GaugeBarBlurRadiusChange
+  end
+  object Panel1: TPanel
+    Left = 0
+    Top = 0
+    Width = 263
+    Height = 26
+    Align = alTop
+    BevelOuter = bvNone
+    ParentColor = True
+    TabOrder = 4
+    object LabelTestImage: TLabel
+      Left = 8
+      Top = 8
+      Width = 62
+      Height = 15
+      Caption = 'Test  Image:'
+    end
+    object RadioButtonRedGreen: TRadioButton
+      Left = 82
+      Top = 7
+      Width = 80
+      Height = 17
+      Caption = 'Red/Green'
+      Checked = True
+      TabOrder = 0
+      TabStop = True
+      OnClick = RadioButtonTestImageClick
+    end
+    object RadioButtonCircles: TRadioButton
+      Left = 175
+      Top = 8
+      Width = 66
+      Height = 17
+      Caption = 'Circles'
+      TabOrder = 1
+      OnClick = RadioButtonTestImageClick
+    end
+  end
+  object CheckBoxUseNew: TCheckBox
+    Left = 8
+    Top = 313
+    Width = 154
+    Height = 17
+    Caption = 'Use new Gaussian blur'
+    Checked = True
+    State = cbChecked
+    TabOrder = 5
+    OnClick = CheckBoxUseNewClick
+  end
+  object CheckBoxGammaSRGB: TCheckBox
+    Left = 82
+    Top = 252
+    Width = 173
+    Height = 17
+    Caption = 'Use sRGB gamma correction'
+    TabOrder = 6
+    OnClick = CheckBoxGammaSRGBClick
+  end
+end

+ 207 - 0
Externals/Graphics32/Examples/Drawing/GammaBlur/MainUnit.pas

@@ -0,0 +1,207 @@
+unit MainUnit;
+
+interface
+
+uses
+  {$IFNDEF FPC} Windows, {$ELSE} LCLIntf, LCLType, {$ENDIF}
+  SysUtils, Classes, Graphics, Controls, Forms, Menus, Dialogs, ComCtrls,
+  ExtCtrls, StdCtrls, Math,
+  GR32, GR32_Image, GR32_Layers, GR32_RangeBars;
+
+type
+  TFormGammaBlur = class(TForm)
+    PaintBoxIncorrect: TPaintBox32;
+    LabelIncorrect: TLabel;
+    LabelCorrect: TLabel;
+    PaintBoxCorrect: TPaintBox32;
+    GaugeBarGamma: TGaugeBar;
+    LabelGamma: TLabel;
+    LabelGammaValue: TLabel;
+    GaugeBarBlurRadius: TGaugeBar;
+    LabelBlur: TLabel;
+    LabelBlurValue: TLabel;
+    Panel1: TPanel;
+    LabelTestImage: TLabel;
+    RadioButtonRedGreen: TRadioButton;
+    RadioButtonCircles: TRadioButton;
+    CheckBoxUseNew: TCheckBox;
+    CheckBoxGammaSRGB: TCheckBox;
+    procedure PaintBoxIncorrectPaintBuffer(Sender: TObject);
+    procedure PaintBoxCorrectPaintBuffer(Sender: TObject);
+    procedure GaugeBarGammaChange(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+    procedure GaugeBarBlurRadiusChange(Sender: TObject);
+    procedure PaintBoxResize(Sender: TObject);
+    procedure RadioButtonTestImageClick(Sender: TObject);
+    procedure CheckBoxUseNewClick(Sender: TObject);
+    procedure CheckBoxGammaSRGBClick(Sender: TObject);
+  private
+    FTestBitmap: TBitmap32;
+    procedure ComposeTestImage;
+    procedure UpdateGamma;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+  end;
+
+var
+  FormGammaBlur: TFormGammaBlur;
+
+implementation
+
+{$IFDEF FPC}
+{$R *.lfm}
+{$ELSE}
+{$R *.dfm}
+{$ENDIF}
+
+uses
+  GR32_Math,
+  GR32_Polygons,
+  GR32_VectorUtils,
+  GR32_Gamma,
+  GR32_System,
+  GR32_Blurs,
+  GR32.Blur,
+  GR32_Resamplers;
+
+{ TFrmGammaBlur }
+
+constructor TFormGammaBlur.Create(AOwner: TComponent);
+begin
+  inherited;
+  PaintBoxIncorrect.BufferOversize := 0;
+  PaintBoxCorrect.BufferOversize := 0;
+  FTestBitmap := TBitmap32.Create;
+end;
+
+destructor TFormGammaBlur.Destroy;
+begin
+  FTestBitmap.Free;
+
+  inherited;
+end;
+
+procedure TFormGammaBlur.FormCreate(Sender: TObject);
+begin
+  GaugeBarGammaChange(nil);
+  GaugeBarBlurRadiusChange(nil);
+  // Ensure controls are same size in case we messed up at design-time
+  PaintBoxIncorrect.Width := PaintBoxCorrect.Width;
+  PaintBoxIncorrect.Height := PaintBoxCorrect.Height;
+end;
+
+procedure TFormGammaBlur.GaugeBarBlurRadiusChange(Sender: TObject);
+var
+  BlurRadius: Double;
+begin
+  BlurRadius := 0.1 * GaugeBarBlurRadius.Position;
+  LabelBlurValue.Caption := Format('%.1n px', [BlurRadius]);
+  PaintBoxIncorrect.Invalidate;
+  PaintBoxCorrect.Invalidate;
+end;
+
+procedure TFormGammaBlur.GaugeBarGammaChange(Sender: TObject);
+begin
+  UpdateGamma;
+end;
+
+procedure ComposeTestImageRedGreen(Bitmap: TBitmap32);
+begin
+  Bitmap.Clear(clRed32);
+  Bitmap.FillRect(0, 0, Bitmap.Width, Bitmap.Height div 2, clLime32);
+end;
+
+procedure ComposeTestImageCircles(Bitmap: TBitmap32);
+var
+  Points: TArrayOfFloatPoint;
+  Index: Integer;
+begin
+  Bitmap.Clear(clBlack32);
+  RandSeed := integer($DEADBABE);
+  for Index := 0 to 70 do
+  begin
+    Points := Circle(Bitmap.Width * Random, Bitmap.Height * Random,
+      0.5 * Min(Bitmap.Width, Bitmap.Height) * Random);
+    PolygonFS(Bitmap, Points, HSLtoRGB(Random, 1, 0.5));
+  end;
+end;
+
+procedure TFormGammaBlur.CheckBoxGammaSRGBClick(Sender: TObject);
+begin
+  UpdateGamma;
+end;
+
+procedure TFormGammaBlur.CheckBoxUseNewClick(Sender: TObject);
+begin
+  PaintBoxCorrect.Invalidate;
+  PaintBoxIncorrect.Invalidate;
+end;
+
+procedure TFormGammaBlur.ComposeTestImage;
+begin
+  if RadioButtonCircles.Checked then
+    ComposeTestImageCircles(FTestBitmap)
+  else
+    ComposeTestImageRedGreen(FTestBitmap);
+end;
+
+procedure TFormGammaBlur.PaintBoxResize(Sender: TObject);
+begin
+  Assert(PaintBoxCorrect.Width = PaintBoxIncorrect.Width);
+  Assert(PaintBoxCorrect.Height = PaintBoxIncorrect.Height);
+  FTestBitmap.SetSize(PaintBoxCorrect.Width, PaintBoxCorrect.Height);
+  ComposeTestImage;
+end;
+
+procedure TFormGammaBlur.RadioButtonTestImageClick(Sender: TObject);
+begin
+  ComposeTestImage;
+  PaintBoxCorrect.Invalidate;
+  PaintBoxIncorrect.Invalidate;
+end;
+
+procedure TFormGammaBlur.UpdateGamma;
+var
+  GammaValue: Double;
+begin
+  GaugeBarGamma.Enabled := (not CheckBoxGammaSRGB.Checked);
+
+  if (CheckBoxGammaSRGB.Checked) then
+  begin
+    Set_sRGB;
+    LabelGammaValue.Caption := 'sRGB';
+  end else
+  begin
+    GammaValue := 0.001 * GaugeBarGamma.Position;
+    LabelGammaValue.Caption := Format('%.3n', [GammaValue]);
+    SetGamma(GammaValue);
+  end;
+
+  PaintBoxIncorrect.Invalidate;
+  PaintBoxCorrect.Invalidate;
+end;
+
+procedure TFormGammaBlur.PaintBoxCorrectPaintBuffer(Sender: TObject);
+begin
+  if CheckBoxUseNew.Checked then
+    GammaBlur32(FTestBitmap, PaintBoxCorrect.Buffer, 0.1 * GaugeBarBlurRadius.Position)
+  else
+  begin
+    FTestBitmap.DrawTo(PaintBoxCorrect.Buffer);
+    GaussianBlurGamma(PaintBoxCorrect.Buffer, 0.1 * GaugeBarBlurRadius.Position);
+  end;
+end;
+
+procedure TFormGammaBlur.PaintBoxIncorrectPaintBuffer(Sender: TObject);
+begin
+  if CheckBoxUseNew.Checked then
+    Blur32(FTestBitmap, PaintBoxIncorrect.Buffer, 0.1 * GaugeBarBlurRadius.Position)
+  else
+  begin
+    FTestBitmap.DrawTo(PaintBoxIncorrect.Buffer);
+    GaussianBlur(PaintBoxIncorrect.Buffer, 0.1 * GaugeBarBlurRadius.Position);
+  end;
+end;
+
+end.

+ 3 - 0
Externals/Graphics32/Examples/Drawing/GammaBlur/Media.rc

@@ -0,0 +1,3 @@
+MainIcon ICON "../../Media/GR32.ico"
+ICELAND JPG "../../Media/iceland.jpg"
+STONEWEED JPG "../../Media/stoneweed.jpg"

+ 14 - 0
Externals/Graphics32/Examples/Drawing/GammaCorrection/GammaCorrection.dpr

@@ -0,0 +1,14 @@
+program GammaCorrection;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFrmGammaCorrection, FrmGammaCorrection);
+  Application.Run;
+end.
+

+ 167 - 0
Externals/Graphics32/Examples/Drawing/GammaCorrection/GammaCorrection.dproj

@@ -0,0 +1,167 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>GammaCorrection.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{c376a6ff-5848-458a-8eb2-e2307d6c6673}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">GammaCorrection</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>GammaCorrection</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">GammaCorrection.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 110 - 0
Externals/Graphics32/Examples/Drawing/GammaCorrection/MainUnit.dfm

@@ -0,0 +1,110 @@
+object FrmGammaCorrection: TFrmGammaCorrection
+  Left = 0
+  Top = 0
+  Caption = 'Gamma Test'
+  ClientHeight = 389
+  ClientWidth = 492
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object PaintBox32: TPaintBox32
+    Left = 0
+    Top = 0
+    Width = 492
+    Height = 317
+    Align = alClient
+    TabOrder = 0
+    OnPaintBuffer = PaintBox32PaintBuffer
+  end
+  object PnControl: TPanel
+    Left = 0
+    Top = 317
+    Width = 492
+    Height = 72
+    Align = alBottom
+    BevelOuter = bvNone
+    ShowCaption = False
+    TabOrder = 1
+    object LblContrast: TLabel
+      Left = 8
+      Top = 8
+      Width = 42
+      Height = 13
+      Caption = 'Contrast'
+    end
+    object LblGamma: TLabel
+      Left = 8
+      Top = 30
+      Width = 35
+      Height = 13
+      Caption = 'Gamma'
+    end
+    object LblThickness: TLabel
+      Left = 8
+      Top = 52
+      Width = 46
+      Height = 13
+      Caption = 'Thickness'
+    end
+    object LblContrastValue: TLabel
+      Left = 439
+      Top = 8
+      Width = 3
+      Height = 13
+    end
+    object LblGammaValue: TLabel
+      Left = 439
+      Top = 30
+      Width = 3
+      Height = 13
+    end
+    object LblThicknessValue: TLabel
+      Left = 439
+      Top = 51
+      Width = 3
+      Height = 13
+    end
+    object GbrContrast: TGaugeBar
+      Left = 56
+      Top = 6
+      Width = 377
+      Height = 16
+      Backgnd = bgPattern
+      Max = 255
+      ShowHandleGrip = True
+      Position = 255
+      OnChange = GbrContrastChange
+    end
+    object GbrGamma: TGaugeBar
+      Left = 56
+      Top = 30
+      Width = 377
+      Height = 16
+      Backgnd = bgPattern
+      LargeChange = 100
+      Max = 3000
+      Min = 300
+      ShowHandleGrip = True
+      Position = 1000
+      OnChange = GbrGammaChange
+    end
+    object GbrThickness: TGaugeBar
+      Left = 56
+      Top = 50
+      Width = 377
+      Height = 16
+      Backgnd = bgPattern
+      Max = 300
+      ShowHandleGrip = True
+      Position = 200
+      OnChange = GbrThicknessChange
+    end
+  end
+end

+ 152 - 0
Externals/Graphics32/Examples/Drawing/GammaCorrection/MainUnit.pas

@@ -0,0 +1,152 @@
+unit MainUnit;
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFDEF FPC}LCLIntf, {$ELSE}Windows, {$ENDIF} Messages, SysUtils, Classes,
+  Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, GR32, GR32_Image,
+  GR32_RangeBars;
+
+type
+  TFrmGammaCorrection = class(TForm)
+    GbrContrast: TGaugeBar;
+    GbrGamma: TGaugeBar;
+    GbrThickness: TGaugeBar;
+    LblContrast: TLabel;
+    LblContrastValue: TLabel;
+    LblGamma: TLabel;
+    LblGammaValue: TLabel;
+    LblThickness: TLabel;
+    LblThicknessValue: TLabel;
+    PaintBox32: TPaintBox32;
+    PnControl: TPanel;
+    procedure FormShow(Sender: TObject);
+    procedure GbrContrastChange(Sender: TObject);
+    procedure GbrGammaChange(Sender: TObject);
+    procedure GbrThicknessChange(Sender: TObject);
+    procedure PaintBox32PaintBuffer(Sender: TObject);
+  end;
+
+var
+  FrmGammaCorrection: TFrmGammaCorrection;
+
+implementation
+
+uses
+  Types,
+  GR32_LowLevel,
+  GR32_Gamma,
+  GR32_VectorUtils,
+  GR32_Polygons;
+
+{$R *.dfm}
+
+procedure TFrmGammaCorrection.FormShow(Sender: TObject);
+begin
+  GbrContrastChange(Sender);
+  GbrGammaChange(Sender);
+  GbrThicknessChange(Sender);
+end;
+
+procedure TFrmGammaCorrection.GbrContrastChange(Sender: TObject);
+begin
+  LblContrastValue.Caption := IntToStr(GbrContrast.Position);
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGammaCorrection.GbrGammaChange(Sender: TObject);
+var
+  GammaValue: Double;
+begin
+  GammaValue := 0.001 * GbrGamma.Position;
+  LblGammaValue.Caption := FloatToStrF(GammaValue, ffFixed, 4, 3);
+  SetGamma(GammaValue);
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGammaCorrection.GbrThicknessChange(Sender: TObject);
+begin
+  LblThicknessValue.Caption := FloatToStrF(0.01 * GbrThickness.Position,
+    ffFixed, 3, 3);
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGammaCorrection.PaintBox32PaintBuffer(Sender: TObject);
+var
+  Renderer: TPolygonRenderer32VPR;
+  W, H: Integer;
+  Thickness: TFloat;
+  Color: TColor32;
+  Outline: TArrayOfFloatPoint;
+  Radius: TFloatPoint;
+  Index, Contrast, DeltaY: Byte;
+  StartPnt: TFloatPoint;
+begin
+  W := PaintBox32.Width;
+  H := PaintBox32.Height;
+  Thickness := 0.01 * GbrThickness.Position;
+  Radius := FloatPoint(W / 3, H / 3);
+  Renderer := TPolygonRenderer32VPR.Create;
+  try
+    Renderer.Bitmap := PaintBox32.Buffer;
+
+    Contrast := $FF - GbrContrast.Position;
+
+    Color := Gray32(Contrast);
+    PaintBox32.Buffer.FillRect(0, 0, Trunc(W) div 2, Trunc(H), Color);
+
+    Color := Gray32($FF - Contrast);
+    PaintBox32.Buffer.FillRect(Trunc(W) div 2, 0, Trunc(W), Trunc(H),
+      Color);
+
+    Color := Color32($FF, Contrast, Contrast);
+    PaintBox32.Buffer.FillRect(0, 0, Trunc(W), Trunc(H) div 2, Color);
+
+    Renderer.Color := Color32($50, $7F, $50);
+    StartPnt := FloatPoint((W - 256) * 0.5, 50);
+
+    SetLength(Outline, 256);
+    for Index := 0 to High(Byte) do
+    begin
+      DeltaY := GAMMA_ENCODING_TABLE[Index];
+
+      Outline[Index] := FloatPoint(StartPnt.X + Index, StartPnt.Y + 255 - DeltaY)
+    end;
+    Renderer.PolygonFS(BuildPolyline(Outline, Thickness));
+
+    Renderer.Color := Color32($FF, 0, 0);
+    Outline := Ellipse(FloatPoint(W * 0.5, H * 0.5), Radius, 150);
+    Renderer.PolyPolygonFS(BuildPolyPolyLine(PolyPolygon(Outline), True,
+      Thickness));
+
+    Renderer.Color := Color32(0, $FF, 0);
+    Outline := Ellipse(FloatPoint(W * 0.5, H * 0.5),
+      FloatPoint(Radius.X - 5, Radius.Y - 5), 150);
+    Renderer.PolyPolygonFS(BuildPolyPolyLine(PolyPolygon(Outline), True,
+      Thickness));
+
+    Renderer.Color := Color32(0, 0, $FF);
+    Outline := Ellipse(FloatPoint(W * 0.5, H * 0.5),
+      FloatPoint(Radius.X - 10, Radius.Y - 10), 150);
+    Renderer.PolyPolygonFS(BuildPolyPolyLine(PolyPolygon(Outline), True,
+      Thickness));
+
+    Renderer.Color := clBlack32;
+    Outline := Ellipse(FloatPoint(W * 0.5, H * 0.5),
+      FloatPoint(Radius.X - 15, Radius.Y - 15), 150);
+    Renderer.PolyPolygonFS(BuildPolyPolyLine(PolyPolygon(Outline), True,
+      Thickness));
+
+    Renderer.Color := clWhite32;
+    Outline := Ellipse(FloatPoint(W * 0.5, H * 0.5),
+      FloatPoint(Radius.X - 20, Radius.Y - 20), 150);
+    Renderer.PolyPolygonFS(BuildPolyPolyLine(PolyPolygon(Outline), True,
+      Thickness));
+  finally
+    Renderer.Free;
+  end;
+end;
+
+end.

+ 1 - 0
Externals/Graphics32/Examples/Drawing/GammaCorrection/Media.rc

@@ -0,0 +1 @@
+MainIcon ICON "../../Media/GR32.ico"

+ 13 - 0
Externals/Graphics32/Examples/Drawing/GradFills/GradFills.dpr

@@ -0,0 +1,13 @@
+program GradFills;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TMainForm, MainForm);
+  Application.Run;
+end.

+ 147 - 0
Externals/Graphics32/Examples/Drawing/GradFills/GradFills.dproj

@@ -0,0 +1,147 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>GradFills.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{7aeb022c-08ec-42d5-8e28-6414bd85d971}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">GradFills</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>GradFills</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">GradFills.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 285 - 0
Externals/Graphics32/Examples/Drawing/GradFills/MainUnit.dfm

@@ -0,0 +1,285 @@
+object MainForm: TMainForm
+  Left = 225
+  Top = 177
+  BorderIcons = [biSystemMenu, biMinimize]
+  BorderStyle = bsSingle
+  Caption = 'Filling Polygons with Color Gradients'
+  ClientHeight = 489
+  ClientWidth = 571
+  Color = clBtnFace
+  Font.Charset = ANSI_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -12
+  Font.Name = 'Arial'
+  Font.Style = []
+  KeyPreview = True
+  Menu = MainMenu
+  OnCreate = FormCreate
+  OnDestroy = FormDestroy
+  OnKeyPress = FormKeyPress
+  TextHeight = 15
+  object PnlControl: TPanel
+    Left = 0
+    Top = 0
+    Width = 145
+    Height = 489
+    Align = alLeft
+    ParentBackground = False
+    TabOrder = 0
+    ExplicitHeight = 464
+    object LblColorStopsTop: TLabel
+      Left = 14
+      Top = 15
+      Width = 68
+      Height = 15
+      Caption = 'Color Stops:'
+      FocusControl = MemoColorStops
+    end
+    object LblLookupTableOrder: TLabel
+      Left = 14
+      Top = 225
+      Width = 111
+      Height = 15
+      Caption = 'Lookup Table Order:'
+    end
+    object MemoColorStops: TMemo
+      Left = 14
+      Top = 38
+      Width = 114
+      Height = 139
+      Lines.Strings = (
+        '0.0: clRed32'
+        '0.1: clYellow32'
+        '0.3: clLime32'
+        '0.5: $AA00FFFF'
+        '0.7: clBlue32'
+        '0.9: clFuchsia32'
+        '1.0: $80FF0000')
+      TabOrder = 0
+      WordWrap = False
+      OnChange = MemoColorStopsChange
+    end
+    object RgpEllipseFillStyle: TRadioGroup
+      Left = 14
+      Top = 400
+      Width = 114
+      Height = 69
+      Caption = 'Radial &Fill Style'
+      ItemIndex = 1
+      Items.Strings = (
+        'Simple'
+        'SVG')
+      ParentBackground = False
+      TabOrder = 1
+      OnClick = RgpEllipseFillStyleClick
+    end
+    object RgpWrapMode: TRadioGroup
+      Left = 14
+      Top = 272
+      Width = 114
+      Height = 122
+      Caption = '&Wrap Mode'
+      ItemIndex = 0
+      Items.Strings = (
+        'Clamp'
+        'Repeat'
+        'Mirror'
+        'Reflect')
+      ParentBackground = False
+      TabOrder = 2
+      OnClick = RgpWrapModeClick
+    end
+    object BtnDefaults: TButton
+      Left = 34
+      Top = 183
+      Width = 75
+      Height = 25
+      Caption = '&Defaults'
+      TabOrder = 3
+      OnClick = BtnDefaultsClick
+    end
+    object CmbLUT: TComboBox
+      Left = 14
+      Top = 243
+      Width = 114
+      Height = 23
+      ItemIndex = 5
+      TabOrder = 4
+      Text = '9 (= 512 Values)'
+      OnChange = CmbLUTChange
+      Items.Strings = (
+        '4 (= 16 Values)'
+        '5 (= 32 Values)'
+        '6 (= 64 Values)'
+        '7 (= 128 Values)'
+        '8 (= 256 Values)'
+        '9 (= 512 Values)'
+        '10 (= 1024 Values)'
+        '11 (= 2048 Values)'
+        '12 (= 4096 Values)'
+        '13 (= 8192 Values)')
+    end
+  end
+  object ImgView32: TImgView32
+    Left = 145
+    Top = 0
+    Width = 426
+    Height = 489
+    Align = alClient
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baTile
+    RepaintMode = rmOptimizer
+    Scale = 1.000000000000000000
+    ScaleMode = smNormal
+    ScrollBars.Increment = 0
+    ScrollBars.Size = 16
+    ScrollBars.Visibility = svHidden
+    OverSize = 0
+    TabOrder = 1
+    OnDblClick = ImgView32DblClick
+    OnMouseDown = ImgView32MouseDown
+    OnMouseMove = ImgView32MouseMove
+    OnMouseUp = ImgView32MouseUp
+    ExplicitWidth = 418
+    ExplicitHeight = 464
+  end
+  object MainMenu: TMainMenu
+    Left = 193
+    Top = 16
+    object MnuFile: TMenuItem
+      Caption = '&File'
+      object MnuFileOpen: TMenuItem
+        Caption = 'Open...'
+        OnClick = MnuFileOpenClick
+      end
+      object MnuFileSaveAs: TMenuItem
+        Caption = 'Save As...'
+        OnClick = MnuFileSaveAsClick
+      end
+      object N1: TMenuItem
+        Caption = '-'
+      end
+      object MnuExit: TMenuItem
+        Caption = 'E&xit'
+        ShortCut = 27
+        OnClick = BtnExitClick
+      end
+    end
+    object MnuWrapMode: TMenuItem
+      Caption = '&Wrap Mode'
+      object MnuClamp: TMenuItem
+        Caption = '&Clamp'
+        Checked = True
+        RadioItem = True
+        OnClick = MnuSpreadClick
+      end
+      object MnuRepeat: TMenuItem
+        Tag = 1
+        Caption = '&Repeat'
+        RadioItem = True
+        OnClick = MnuSpreadClick
+      end
+      object MnuMirror: TMenuItem
+        Tag = 2
+        Caption = '&Mirror'
+        RadioItem = True
+        OnClick = MnuSpreadClick
+      end
+      object MnuReflect: TMenuItem
+        Tag = 3
+        Caption = 'Reflect'
+        RadioItem = True
+        OnClick = MnuSpreadClick
+      end
+    end
+    object MnuRadialFillStyle: TMenuItem
+      Caption = 'Radial &Fill Style'
+      object MnuSimple: TMenuItem
+        Caption = '&Simple'
+        RadioItem = True
+        OnClick = MnuRadialFillStyleClick
+      end
+      object MnuSVG: TMenuItem
+        Tag = 1
+        Caption = 'S&VG'
+        Checked = True
+        RadioItem = True
+        OnClick = MnuRadialFillStyleClick
+      end
+    end
+    object MnuLookupTableOrder: TMenuItem
+      Caption = '&Lookup Table Order'
+      object MnuOrder4: TMenuItem
+        Caption = '4 (= 16 Values)'
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+      object MnuOrder5: TMenuItem
+        Tag = 1
+        Caption = '5 (= 32 Values)'
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+      object MnuOrder6: TMenuItem
+        Tag = 2
+        Caption = '6 (= 64 Values)'
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+      object MnuOrder7: TMenuItem
+        Tag = 3
+        Caption = '7 (= 128 Values)'
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+      object MnuOrder8: TMenuItem
+        Tag = 4
+        Caption = '8 (= 256 Values)'
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+      object MnuOrder9: TMenuItem
+        Tag = 5
+        Caption = '9 (= 512 Values)'
+        Checked = True
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+      object MnuOrder10: TMenuItem
+        Tag = 6
+        Caption = '10 (= 1024 Values)'
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+      object MnuOrder11: TMenuItem
+        Tag = 7
+        Caption = '11 (= 2048 Values)'
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+      object MnuOrder12: TMenuItem
+        Tag = 8
+        Caption = '12 (= 4096 Values)'
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+      object MnuOrder13: TMenuItem
+        Tag = 9
+        Caption = '13 (= 8192 Values)'
+        RadioItem = True
+        OnClick = MnuOrderClick
+      end
+    end
+  end
+  object OpenDialog: TOpenDialog
+    DefaultExt = '.stops.txt'
+    Left = 192
+    Top = 80
+  end
+  object SaveDialog: TSaveDialog
+    DefaultExt = '.stops.txt'
+    Filter = 'Color Stops (*.stops.txt)|*.stops.txt'
+    Left = 192
+    Top = 136
+  end
+end

+ 829 - 0
Externals/Graphics32/Examples/Drawing/GradFills/MainUnit.pas

@@ -0,0 +1,829 @@
+unit MainUnit;
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFDEF FPC} LCLIntf, LCLType, {$ELSE} Windows, {$ENDIF} SysUtils, Types,
+  Classes, Graphics, Controls, Forms, Dialogs, Math, ExtCtrls, StdCtrls, Menus,
+  GR32, GR32_Polygons, GR32_Image, GR32_Layers, GR32_Transforms,
+  GR32_ColorGradients;
+
+type
+  TMainForm = class(TForm)
+    BtnDefaults: TButton;
+    CmbLUT: TComboBox;
+    ImgView32: TImgView32;
+    LblColorStopsTop: TLabel;
+    LblLookupTableOrder: TLabel;
+    MainMenu: TMainMenu;
+    MemoColorStops: TMemo;
+    MnuExit: TMenuItem;
+    MnuFile: TMenuItem;
+    MnuFileOpen: TMenuItem;
+    MnuFileSaveAs: TMenuItem;
+    MnuLookupTableOrder: TMenuItem;
+    MnuOrder4: TMenuItem;
+    MnuOrder5: TMenuItem;
+    MnuOrder6: TMenuItem;
+    MnuOrder7: TMenuItem;
+    MnuOrder8: TMenuItem;
+    MnuOrder9: TMenuItem;
+    MnuOrder10: TMenuItem;
+    MnuOrder11: TMenuItem;
+    MnuOrder12: TMenuItem;
+    MnuOrder13: TMenuItem;
+    MnuClamp: TMenuItem;
+    MnuRadialFillStyle: TMenuItem;
+    MnuMirror: TMenuItem;
+    MnuRepeat: TMenuItem;
+    MnuSimple: TMenuItem;
+    MnuWrapMode: TMenuItem;
+    MnuSVG: TMenuItem;
+    N1: TMenuItem;
+    OpenDialog: TOpenDialog;
+    PnlControl: TPanel;
+    RgpEllipseFillStyle: TRadioGroup;
+    RgpWrapMode: TRadioGroup;
+    SaveDialog: TSaveDialog;
+    MnuReflect: TMenuItem;
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+    procedure FormKeyPress(Sender: TObject; var Key: Char);
+    procedure BtnDefaultsClick(Sender: TObject);
+    procedure BtnExitClick(Sender: TObject);
+    procedure CmbLUTChange(Sender: TObject);
+    procedure ImgView32DblClick(Sender: TObject);
+    procedure ImgView32MouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+    procedure ImgView32MouseUp(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+    procedure ImgView32MouseMove(Sender: TObject; Shift: TShiftState; X,
+      Y: Integer; Layer: TCustomLayer);
+    procedure MemoColorStopsChange(Sender: TObject);
+    procedure MnuFileOpenClick(Sender: TObject);
+    procedure MnuFileSaveAsClick(Sender: TObject);
+    procedure MnuOrderClick(Sender: TObject);
+    procedure MnuRadialFillStyleClick(Sender: TObject);
+    procedure MnuSpreadClick(Sender: TObject);
+    procedure RgpEllipseFillStyleClick(Sender: TObject);
+    procedure RgpWrapModeClick(Sender: TObject);
+  private
+    FDpiScale: single;
+    FKnobBitmap: TBitmap32;
+    FKnobRadius: Integer;
+    FControlKnob: PPoint;
+    FLinearStart: TPoint;
+    FLinearEnd: TPoint;
+    FRadialOrigin: TPoint;
+    FRadialX: TPoint;
+    FRadialY: TPoint;
+
+    FLinearBounds: TRect;
+    FRadialBounds: TRect;
+    FGradient: TColor32Gradient;
+    FGradientLUT: TColor32LookupTable;
+    FTextNotesPoly: TArrayOfArrayOfFloatPoint;
+    FTextTopPoly: TArrayOfArrayOfFloatPoint;
+    FTextBottomPoly: TArrayOfArrayOfFloatPoint;
+    FTextGR32: TArrayOfArrayOfFloatPoint;
+    procedure LUTOrderChangedHandler(Sender: TObject);
+  public
+    procedure DrawImage;
+  end;
+
+var
+  MainForm: TMainForm;
+
+implementation
+
+{$R *.dfm}
+
+{.$R data.res}
+
+uses
+  GR32_Math,
+  GR32_Geometry,
+  GR32_VectorUtils,
+  GR32_Gamma,
+  GR32_Paths,
+  GR32_Backends;
+
+const
+  Colors: array[0..147] of TIdentMapEntry = (
+    (Value: Integer($FF000000); Name: 'clBlack32'),
+    (Value: Integer($FF3F3F3F); Name: 'clDimGray32'),
+    (Value: Integer($FF7F7F7F); Name: 'clGray32'),
+    (Value: Integer($FFBFBFBF); Name: 'clLightGray32'),
+    (Value: Integer($FFFFFFFF); Name: 'clWhite32'),
+    (Value: Integer($FF7F0000); Name: 'clMaroon32'),
+    (Value: Integer($FF007F00); Name: 'clGreen32'),
+    (Value: Integer($FF7F7F00); Name: 'clOlive32'),
+    (Value: Integer($FF00007F); Name: 'clNavy32'),
+    (Value: Integer($FF7F007F); Name: 'clPurple32'),
+    (Value: Integer($FF007F7F); Name: 'clTeal32'),
+    (Value: Integer($FFFF0000); Name: 'clRed32'),
+    (Value: Integer($FF00FF00); Name: 'clLime32'),
+    (Value: Integer($FFFFFF00); Name: 'clYellow32'),
+    (Value: Integer($FF0000FF); Name: 'clBlue32'),
+    (Value: Integer($FFFF00FF); Name: 'clFuchsia32'),
+    (Value: Integer($FF00FFFF); Name: 'clAqua32'),
+    (Value: Integer($FFF0F8FF); Name: 'clAliceBlue32'),
+    (Value: Integer($FFFAEBD7); Name: 'clAntiqueWhite32'),
+    (Value: Integer($FF7FFFD4); Name: 'clAquamarine32'),
+    (Value: Integer($FFF0FFFF); Name: 'clAzure32'),
+    (Value: Integer($FFF5F5DC); Name: 'clBeige32'),
+    (Value: Integer($FFFFE4C4); Name: 'clBisque32'),
+    (Value: Integer($FFFFEBCD); Name: 'clBlancheDalmond32'),
+    (Value: Integer($FF8A2BE2); Name: 'clBlueViolet32'),
+    (Value: Integer($FFA52A2A); Name: 'clBrown32'),
+    (Value: Integer($FFDEB887); Name: 'clBurlyWood32'),
+    (Value: Integer($FF5F9EA0); Name: 'clCadetblue32'),
+    (Value: Integer($FF7FFF00); Name: 'clChartReuse32'),
+    (Value: Integer($FFD2691E); Name: 'clChocolate32'),
+    (Value: Integer($FFFF7F50); Name: 'clCoral32'),
+    (Value: Integer($FF6495ED); Name: 'clCornFlowerBlue32'),
+    (Value: Integer($FFFFF8DC); Name: 'clCornSilk32'),
+    (Value: Integer($FFDC143C); Name: 'clCrimson32'),
+    (Value: Integer($FF00008B); Name: 'clDarkBlue32'),
+    (Value: Integer($FF008B8B); Name: 'clDarkCyan32'),
+    (Value: Integer($FFB8860B); Name: 'clDarkGoldenRod32'),
+    (Value: Integer($FFA9A9A9); Name: 'clDarkGray32'),
+    (Value: Integer($FF006400); Name: 'clDarkGreen32'),
+    (Value: Integer($FFA9A9A9); Name: 'clDarkGrey32'),
+    (Value: Integer($FFBDB76B); Name: 'clDarkKhaki32'),
+    (Value: Integer($FF8B008B); Name: 'clDarkMagenta32'),
+    (Value: Integer($FF556B2F); Name: 'clDarkOliveGreen32'),
+    (Value: Integer($FFFF8C00); Name: 'clDarkOrange32'),
+    (Value: Integer($FF9932CC); Name: 'clDarkOrchid32'),
+    (Value: Integer($FF8B0000); Name: 'clDarkRed32'),
+    (Value: Integer($FFE9967A); Name: 'clDarkSalmon32'),
+    (Value: Integer($FF8FBC8F); Name: 'clDarkSeaGreen32'),
+    (Value: Integer($FF483D8B); Name: 'clDarkSlateBlue32'),
+    (Value: Integer($FF2F4F4F); Name: 'clDarkSlateGray32'),
+    (Value: Integer($FF2F4F4F); Name: 'clDarkSlateGrey32'),
+    (Value: Integer($FF00CED1); Name: 'clDarkTurquoise32'),
+    (Value: Integer($FF9400D3); Name: 'clDarkViolet32'),
+    (Value: Integer($FFFF1493); Name: 'clDeepPink32'),
+    (Value: Integer($FF00BFFF); Name: 'clDeepSkyBlue32'),
+    (Value: Integer($FF1E90FF); Name: 'clDodgerBlue32'),
+    (Value: Integer($FFB22222); Name: 'clFireBrick32'),
+    (Value: Integer($FFFFFAF0); Name: 'clFloralWhite32'),
+    (Value: Integer($FFDCDCDC); Name: 'clGainsBoro32'),
+    (Value: Integer($FFF8F8FF); Name: 'clGhostWhite32'),
+    (Value: Integer($FFFFD700); Name: 'clGold32'),
+    (Value: Integer($FFDAA520); Name: 'clGoldenRod32'),
+    (Value: Integer($FFADFF2F); Name: 'clGreenYellow32'),
+    (Value: Integer($FF808080); Name: 'clGrey32'),
+    (Value: Integer($FFF0FFF0); Name: 'clHoneyDew32'),
+    (Value: Integer($FFFF69B4); Name: 'clHotPink32'),
+    (Value: Integer($FFCD5C5C); Name: 'clIndianRed32'),
+    (Value: Integer($FF4B0082); Name: 'clIndigo32'),
+    (Value: Integer($FFFFFFF0); Name: 'clIvory32'),
+    (Value: Integer($FFF0E68C); Name: 'clKhaki32'),
+    (Value: Integer($FFE6E6FA); Name: 'clLavender32'),
+    (Value: Integer($FFFFF0F5); Name: 'clLavenderBlush32'),
+    (Value: Integer($FF7CFC00); Name: 'clLawnGreen32'),
+    (Value: Integer($FFFFFACD); Name: 'clLemonChiffon32'),
+    (Value: Integer($FFADD8E6); Name: 'clLightBlue32'),
+    (Value: Integer($FFF08080); Name: 'clLightCoral32'),
+    (Value: Integer($FFE0FFFF); Name: 'clLightCyan32'),
+    (Value: Integer($FFFAFAD2); Name: 'clLightGoldenRodYellow32'),
+    (Value: Integer($FF90EE90); Name: 'clLightGreen32'),
+    (Value: Integer($FFD3D3D3); Name: 'clLightGrey32'),
+    (Value: Integer($FFFFB6C1); Name: 'clLightPink32'),
+    (Value: Integer($FFFFA07A); Name: 'clLightSalmon32'),
+    (Value: Integer($FF20B2AA); Name: 'clLightSeagreen32'),
+    (Value: Integer($FF87CEFA); Name: 'clLightSkyblue32'),
+    (Value: Integer($FF778899); Name: 'clLightSlategray32'),
+    (Value: Integer($FF778899); Name: 'clLightSlategrey32'),
+    (Value: Integer($FFB0C4DE); Name: 'clLightSteelblue32'),
+    (Value: Integer($FFFFFFE0); Name: 'clLightYellow32'),
+    (Value: Integer($FFC0C0C0); Name: 'clLtGray32'),
+    (Value: Integer($FFA0A0A4); Name: 'clMedGray32'),
+    (Value: Integer($FF808080); Name: 'clDkGray32'),
+    (Value: Integer($FFC0DCC0); Name: 'clMoneyGreen32'),
+    (Value: Integer($FFA6CAF0); Name: 'clLegacySkyBlue32'),
+    (Value: Integer($FFFFFBF0); Name: 'clCream32'),
+    (Value: Integer($FF32CD32); Name: 'clLimeGreen32'),
+    (Value: Integer($FFFAF0E6); Name: 'clLinen32'),
+    (Value: Integer($FF66CDAA); Name: 'clMediumAquamarine32'),
+    (Value: Integer($FF0000CD); Name: 'clMediumBlue32'),
+    (Value: Integer($FFBA55D3); Name: 'clMediumOrchid32'),
+    (Value: Integer($FF9370DB); Name: 'clMediumPurple32'),
+    (Value: Integer($FF3CB371); Name: 'clMediumSeaGreen32'),
+    (Value: Integer($FF7B68EE); Name: 'clMediumSlateBlue32'),
+    (Value: Integer($FF00FA9A); Name: 'clMediumSpringGreen32'),
+    (Value: Integer($FF48D1CC); Name: 'clMediumTurquoise32'),
+    (Value: Integer($FFC71585); Name: 'clMediumVioletRed32'),
+    (Value: Integer($FF191970); Name: 'clMidnightBlue32'),
+    (Value: Integer($FFF5FFFA); Name: 'clMintCream32'),
+    (Value: Integer($FFFFE4E1); Name: 'clMistyRose32'),
+    (Value: Integer($FFFFE4B5); Name: 'clMoccasin32'),
+    (Value: Integer($FFFFDEAD); Name: 'clNavajoWhite32'),
+    (Value: Integer($FFFDF5E6); Name: 'clOldLace32'),
+    (Value: Integer($FF6B8E23); Name: 'clOliveDrab32'),
+    (Value: Integer($FFFFA500); Name: 'clOrange32'),
+    (Value: Integer($FFFF4500); Name: 'clOrangeRed32'),
+    (Value: Integer($FFDA70D6); Name: 'clOrchid32'),
+    (Value: Integer($FFEEE8AA); Name: 'clPaleGoldenRod32'),
+    (Value: Integer($FF98FB98); Name: 'clPaleGreen32'),
+    (Value: Integer($FFAFEEEE); Name: 'clPaleTurquoise32'),
+    (Value: Integer($FFDB7093); Name: 'clPaleVioletred32'),
+    (Value: Integer($FFFFEFD5); Name: 'clPapayaWhip32'),
+    (Value: Integer($FFFFDAB9); Name: 'clPeachPuff32'),
+    (Value: Integer($FFCD853F); Name: 'clPeru32'),
+    (Value: Integer($FFDDA0DD); Name: 'clPlum32'),
+    (Value: Integer($FFB0E0E6); Name: 'clPowderBlue32'),
+    (Value: Integer($FFBC8F8F); Name: 'clRosyBrown32'),
+    (Value: Integer($FF4169E1); Name: 'clRoyalBlue32'),
+    (Value: Integer($FF8B4513); Name: 'clSaddleBrown32'),
+    (Value: Integer($FFFA8072); Name: 'clSalmon32'),
+    (Value: Integer($FFF4A460); Name: 'clSandyBrown32'),
+    (Value: Integer($FF2E8B57); Name: 'clSeaGreen32'),
+    (Value: Integer($FFFFF5EE); Name: 'clSeaShell32'),
+    (Value: Integer($FFA0522D); Name: 'clSienna32'),
+    (Value: Integer($FFC0C0C0); Name: 'clSilver32'),
+    (Value: Integer($FF87CEEB); Name: 'clSkyBlue32'),
+    (Value: Integer($FF6A5ACD); Name: 'clSlateBlue32'),
+    (Value: Integer($FF708090); Name: 'clSlateGray32'),
+    (Value: Integer($FF708090); Name: 'clSlateGrey32'),
+    (Value: Integer($FFFFFAFA); Name: 'clSnow32'),
+    (Value: Integer($FF00FF7F); Name: 'clSpringGreen32'),
+    (Value: Integer($FF4682B4); Name: 'clSteelBlue32'),
+    (Value: Integer($FFD2B48C); Name: 'clTan32'),
+    (Value: Integer($FFD8BFD8); Name: 'clThistle32'),
+    (Value: Integer($FFFF6347); Name: 'clTomato32'),
+    (Value: Integer($FF40E0D0); Name: 'clTurquoise32'),
+    (Value: Integer($FFEE82EE); Name: 'clViolet32'),
+    (Value: Integer($FFF5DEB3); Name: 'clWheat32'),
+    (Value: Integer($FFF5F5F5); Name: 'clWhiteSmoke32'),
+    (Value: Integer($FF9ACD32); Name: 'clYellowGreen32'));
+
+
+{ Miscellaneous functions }
+
+procedure StrToArrayColor32Gradient(s: TStrings; Gradient: TColor32Gradient);
+var
+  I, J: Integer;
+  Offset: TFloat;
+  Color: TColor32;
+  ColorStr: string;
+  LocalFormatSettings: TFormatSettings;
+begin
+  LocalFormatSettings := FormatSettings;
+  LocalFormatSettings.DecimalSeparator := '.';
+
+  Gradient.ClearColorStops;
+  for i := 0 to s.Count - 1 do
+  begin
+    j := Pos(':', s[i]);
+    if j < 2 then
+      Continue;
+    Offset := StrToFloatDef(Copy(s[i], 1, j - 1), -1, LocalFormatSettings);
+    if (Offset < 0) then
+      Continue;
+    ColorStr := Trim(Copy(s[i], j + 1, 80));
+    if not IdentToInt(ColorStr, Integer(Color), Colors) then
+      Color := TColor32(StrToIntDef(ColorStr, $01010101));
+    if Color <> $01010101 then
+      Gradient.AddColorStop(Offset, Color);
+  end;
+end;
+
+function LoadPolysFromResource(const ResName: string): TArrayOfArrayOfFloatPoint;
+var
+  I,J, Count: Integer;
+  ResStream: TResourceStream;
+
+  function ReadInt: Integer;
+  begin
+    ResStream.Read(Result, SizeOf(Result));
+  end;
+
+  function ReadFloatPoint: TFloatPoint;
+  begin
+    ResStream.Read(Result.X, SizeOf(TFloat));
+    ResStream.Read(Result.Y, SizeOf(TFloat));
+  end;
+
+begin
+  ResStream := TResourceStream.Create(hInstance, ResName, RT_RCDATA);
+  try
+    Count := ReadInt;
+    SetLength(Result, Count);
+    for I := 0 to Count - 1 do
+    begin
+      Count := ReadInt;
+      SetLength(Result[I], Count);
+      for J := 0 to Count - 1 do
+        Result[I, J] := ReadFloatPoint;
+    end;
+  finally
+    ResStream.Free;
+  end;
+end;
+
+function DPIScale(value: integer): integer; overload;
+begin
+  result := mulDiv(value, screen.PixelsPerInch, 96);
+end;
+
+function DPIScale(value: single): single; overload;
+begin
+  result := value * screen.PixelsPerInch / 96;
+end;
+
+function DpiAwarePoint(const x, y: integer): TPoint;
+begin
+  result := Gr32.Point(DPIScale(x), DPIScale(y));
+end;
+
+function DpiAwareRect(const l, t, r, b: integer): TRect;
+begin
+  result := Rect(DPIScale(l), DPIScale(t), DPIScale(r), DPIScale(b));
+end;
+
+function DpiAwareFloatPoint(const x, y: integer): TFloatPoint;
+begin
+  result := FloatPoint(DPIScale(x), DPIScale(y));
+end;
+
+function DpiAwareFloatRect(const l, t, r, b: single): TFloatRect;
+begin
+  result := FloatRect(DPIScale(l), DPIScale(t), DPIScale(r), DPIScale(b));
+end;
+
+procedure OffsetPolygon(var polygon: TArrayOfFloatPoint; dx, dy: single);
+var
+  i: integer;
+begin
+  for i := 0 to high(polygon) do
+  begin
+    polygon[i].X := polygon[i].X + dx;
+    polygon[i].Y := polygon[i].Y + dy;
+  end;
+end;
+
+procedure OffsetPolyPolygon(var polygons: TArrayOfArrayOfFloatPoint; dx, dy: single);
+var
+  i: integer;
+begin
+  for i := 0 to high(polygons) do
+    OffsetPolygon(polygons[i], dx, dy);
+end;
+
+{ TMainForm }
+
+procedure TMainForm.FormCreate(Sender: TObject);
+var
+  TextPath: TFlattenedPath;
+  Outline: TArrayOfFloatPoint;
+  Filler: TSamplerFiller;
+  Sampler: TRadialGradientSampler;
+  TextToPath: ITextToPathSupport;
+begin
+
+  if Screen.PixelsPerInch > 96 then
+    FDpiScale := Screen.PixelsPerInch/ 96
+  else
+    FDpiScale := 1;
+
+  ImgView32.SetupBitmap(True, clCream32);
+
+  FLinearBounds := DpiAwareRect(50, 50, 350, 200);
+  FRadialBounds := DpiAwareRect(50, 250, 350, 400);
+
+  FGradient := TColor32Gradient.Create;
+  StrToArrayColor32Gradient(MemoColorStops.Lines, FGradient);
+
+  FGradientLUT := TColor32LookupTable.Create;
+  FGradientLUT.OnOrderChanged := LUTOrderChangedHandler;
+  FGradient.FillColorLookUpTable(FGradientLUT);
+
+  if (Supports(ImgView32.Bitmap.Backend, ITextToPathSupport, TextToPath)) then
+  begin
+    // These text paths only need to be gotten once ...
+    TextPath := TFlattenedPath.Create;
+    try
+      TextToPath.TextToPath(TextPath, DpiAwareFloatRect(50, 10, 450, 30), 'Click & drag control buttons to adjust gradients');
+      FTextNotesPoly := TextPath.Path;
+
+      with FLinearBounds do
+        TextToPath.TextToPath(TextPath, FloatRect(Left, Bottom, Left + DPIScale(150),Bottom + DPIScale(20)), 'Linear gradients');
+      FTextTopPoly := TextPath.Path;
+
+      with FRadialBounds do
+        TextToPath.TextToPath(TextPath, FloatRect(Left, Bottom, Left + DPIScale(150), Bottom + DPIScale(20)), 'Radial gradients');
+      FTextBottomPoly := TextPath.Path;
+    finally
+      TextPath.Free;
+    end;
+  end;
+
+  FTextGR32 := LoadPolysFromResource('Graphics32_Crv');
+  OffsetPolyPolygon(FTextGR32, DPIScale(-42), 0);
+  if FDpiScale > 1 then
+    FTextGR32 := ScalePolyPolygon(FTextGR32, FDpiScale, FDpiScale);
+
+  FKnobRadius := DPIScale(4);
+  FKnobBitmap := TBitmap32.Create;
+  FKnobBitmap.SetSize(2 * FKnobRadius + 2, 2 * FKnobRadius + 2);
+  FKnobBitmap.DrawMode := dmBlend;
+  FKnobBitmap.CombineMode := cmMerge;
+
+  Sampler := TRadialGradientSampler.Create;
+  try
+    Sampler.Gradient.AddColorStop(0.0, $FFFFFFFF);
+    Sampler.Gradient.AddColorStop(1.0, $FFA0A0A0);
+    Sampler.Radius := FKnobRadius + FKnobRadius div 2;
+    Sampler.Center := FloatPoint(FKnobRadius - 1.5, FKnobRadius - 1.5);
+
+    Filler := TSamplerFiller.Create(Sampler);
+    try
+      Filler.Sampler := Sampler;
+
+      Outline := Circle(FKnobRadius + 1, FKnobRadius + 1, FKnobRadius);
+      PolygonFS(FKnobBitmap, Outline, Filler, pfWinding);
+      PolylineFS(FKnobBitmap, Outline, clBlack32, True);
+    finally
+      Filler.Free;
+    end;
+  finally
+    Sampler.Free;
+  end;
+
+  FLinearStart := DpiAwarePoint(100, 125);
+  FLinearEnd  := DpiAwarePoint(300, 125);
+  FRadialOrigin := DpiAwarePoint(250, 350);
+
+  with FRadialOrigin do
+  begin
+    FRadialX := GR32.Point(X - DPIScale(80), Y);
+    FRadialY := GR32.Point(X, Y + DPIScale(40));
+  end;
+
+  DrawImage;
+end;
+
+procedure TMainForm.FormDestroy(Sender: TObject);
+begin
+  FGradient.Free;
+  FKnobBitmap.Free;
+end;
+
+procedure TMainForm.ImgView32DblClick(Sender: TObject);
+begin
+  // Just some test
+  case Random(4) of
+    0:
+      begin
+        FLinearStart := DpiAwarePoint(200, 70);
+        FLinearEnd := DpiAwarePoint(200, 170);
+      end;
+    1:
+      begin
+        FLinearStart := DpiAwarePoint(200, 120);
+        FLinearEnd := DpiAwarePoint(200, 120);
+      end;
+    2:
+      begin
+        FLinearStart := DpiAwarePoint(200, 120);
+        FLinearEnd := DpiAwarePoint(201, 120);
+      end;
+    3:
+      begin
+        FLinearStart := DpiAwarePoint(200, 100);
+        FLinearEnd := DpiAwarePoint(200, 140);
+      end;
+  end;
+
+  FRadialOrigin := DpiAwarePoint(331, 325);
+
+  DrawImage;
+end;
+
+function TestHitPoint(X, Y: Integer; Point: TPoint; Radius: TFloat): Boolean;
+begin
+  Result := Sqr(X - Point.X) + Sqr(Y - Point.Y) < Sqr(Radius);
+end;
+
+procedure TMainForm.ImgView32MouseDown(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+  if TestHitPoint(X, Y, FLinearStart, FKnobRadius) then
+    FControlKnob := @FLinearStart
+  else
+  if TestHitPoint(X, Y, FLinearEnd, FKnobRadius) then
+    FControlKnob := @FLinearEnd
+  else
+  if TestHitPoint(X, Y, FRadialX, FKnobRadius) then
+  begin
+    if ssCtrl in Shift then
+    begin
+      FRadialX.X := FRadialOrigin.X - Abs(FRadialOrigin.Y -
+        FRadialY.Y);
+      DrawImage;
+    end
+    else
+      FControlKnob := @FRadialX;
+  end else
+  if TestHitPoint(X, Y, FRadialY, FKnobRadius) then
+  begin
+    if ssCtrl in Shift then
+    begin
+      FRadialY.Y := FRadialOrigin.Y + Abs(FRadialOrigin.X - FRadialX.X);
+      DrawImage;
+    end
+    else
+      FControlKnob := @FRadialY;
+  end else
+  if TestHitPoint(X, Y, FRadialOrigin, FKnobRadius) then
+    FControlKnob := @FRadialOrigin;
+end;
+
+procedure TMainForm.ImgView32MouseMove(Sender: TObject; Shift: TShiftState;
+  X, Y: Integer; Layer: TCustomLayer);
+var
+  Delta: TPoint;
+begin
+  if FControlKnob = @FLinearStart then
+  begin
+    X := EnsureRange(X, 10, ImgView32.ClientWidth - 10);
+    Y := EnsureRange(Y, 10, ImgView32.ClientHeight - 10);
+    if (Abs(FLinearEnd.X - X) < 1) and (Abs(FLinearEnd.Y - Y) < 1) then
+      Exit;
+    FLinearStart := GR32.Point(X, Y);
+    DrawImage;
+    Screen.Cursor := crHandPoint;
+  end else
+  if FControlKnob = @FLinearEnd then
+  begin
+    X := EnsureRange(X, 10, ImgView32.ClientWidth - 10);
+    Y := EnsureRange(Y, 10, ImgView32.ClientHeight - 10);
+    if (Abs(FLinearStart.X - X) < 1) and (Abs(FLinearStart.Y - Y) < 1) then
+      Exit;
+    FLinearEnd := GR32.Point(X, Y);
+    DrawImage;
+    Screen.Cursor := crHandPoint;
+  end else
+  if FControlKnob = @FRadialOrigin then
+  begin
+    X := EnsureRange(X, FRadialBounds.Left, FRadialBounds.Right);
+    Y := EnsureRange(Y, FRadialBounds.Top, FRadialBounds.Bottom);
+
+    Delta.X := X - FRadialOrigin.X;
+    Delta.Y := Y - FRadialOrigin.Y;
+    FRadialOrigin := GR32.Point(X, Y);
+    FRadialX := OffsetPoint(FRadialX, Delta.X, Delta.Y);
+    FRadialY := OffsetPoint(FRadialY, Delta.X, Delta.Y);
+    DrawImage;
+    Screen.Cursor := crHandPoint;
+  end else
+  if FControlKnob = @FRadialX then
+  begin
+    X := EnsureRange(X, 10, ImgView32.ClientWidth - 10);
+    Delta.X := X - FRadialOrigin.X;
+    if (Abs(Delta.X) < 3) then Exit;
+      FRadialX := GR32.Point(FRadialOrigin.X + Delta.X, FRadialX.Y);
+    DrawImage;
+    Screen.Cursor := crHandPoint;
+  end else
+  if FControlKnob = @FRadialY then
+  begin
+    Y := EnsureRange(Y, 10, ImgView32.ClientHeight - 10);
+    Delta.Y := Y - FRadialOrigin.Y;
+    if (Abs(Delta.Y) < 3) then Exit;
+    FRadialY := GR32.Point(FRadialY.X, FRadialOrigin.Y + Delta.Y);
+    DrawImage;
+    Screen.Cursor := crHandPoint;
+  end else
+  begin
+    if TestHitPoint(X, Y, FLinearStart, FKnobRadius) or
+      TestHitPoint(X, Y, FLinearEnd, FKnobRadius) or
+      TestHitPoint(X, Y, FRadialOrigin, FKnobRadius) or
+      TestHitPoint(X, Y, FRadialX, FKnobRadius) or
+      TestHitPoint(X, Y, FRadialY, FKnobRadius) or
+      Assigned(FControlKnob) then
+    begin
+      Screen.Cursor := crHandPoint;
+      ImgView32.Cursor := crHandPoint;
+    end
+    else
+    begin
+      Screen.Cursor := crDefault;
+      ImgView32.Cursor := crDefault;
+    end;
+  end;
+end;
+
+procedure TMainForm.ImgView32MouseUp(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+  FControlKnob := nil;
+end;
+
+procedure TMainForm.DrawImage;
+var
+  PolygonTop, PolygonBottom: TArrayOfFloatPoint;
+  Delta: TPoint;
+  LinearGradFiller: TCustomLinearGradientPolygonFiller;
+  RadialGradFiller: TRadialGradientPolygonFiller;
+  SVGStyleRadGradFiller: TSVGRadialGradientPolygonFiller;
+const
+  SimpleStyle = 0;
+begin
+  ImgView32.Bitmap.Clear(clCream32);
+  ImgView32.Bitmap.FrameRectTS(FLinearBounds, clSilver32);
+  ImgView32.Bitmap.FrameRectTS(FRadialBounds, clSilver32);
+
+  //draw the top ellipse ...
+  PolygonTop := Ellipse(200, 125, 100, 60);
+  if FDpiScale > 1 then
+    PolygonTop := ScalePolygon(PolygonTop, FDpiScale, FDpiScale);
+
+  LinearGradFiller := TLinearGradientPolygonFiller.Create(FGradientLUT);
+  try
+    LinearGradFiller.StartPoint := FloatPoint(FLinearStart);
+    LinearGradFiller.EndPoint := FloatPoint(FLinearEnd);
+    LinearGradFiller.WrapMode := TWrapMode(RgpWrapMode.ItemIndex);
+
+    PolygonFS(ImgView32.Bitmap, PolygonTop, LinearGradFiller);
+    PolyLineFS(ImgView32.Bitmap, PolygonTop, clBlack32, True, 1);
+
+    //use LinearGradFiller to fill 'Graphics32' text  too ...
+    LinearGradFiller.StartPoint := DpiAwareFloatPoint(230, 420);
+    LinearGradFiller.EndPoint := DpiAwareFloatPoint(430, 420);
+    PolyPolygonFS(ImgView32.Bitmap, FTextGR32, LinearGradFiller);
+    PolyPolylineFS(ImgView32.Bitmap, FTextGR32, clBlack32, True, 1.2);
+  finally
+    LinearGradFiller.Free;
+  end;
+
+  //draw the bottom ellipse ...
+  PolygonBottom := Ellipse(200, 325, 100, 60);
+  if FDpiScale > 1 then
+    PolygonBottom := ScalePolygon(PolygonBottom, FDpiScale, FDpiScale);
+
+  if RgpEllipseFillStyle.ItemIndex = SimpleStyle then
+  begin
+    RadialGradFiller := TRadialGradientPolygonFiller.Create(FGradientLUT);
+    try
+      RadialGradFiller.WrapMode := TWrapMode(RgpWrapMode.ItemIndex);
+      Delta.X := Abs(FRadialOrigin.X - FRadialX.X);
+      Delta.Y := Abs(FRadialOrigin.Y - FRadialY.Y);
+      with FRadialOrigin do
+        RadialGradFiller.EllipseBounds := FloatRect(X - Delta.X, Y - Delta.Y,
+          X + Delta.X, Y + Delta.Y);
+      PolygonFS(ImgView32.Bitmap, PolygonBottom, RadialGradFiller);
+    finally
+      RadialGradFiller.Free;
+    end;
+  end else
+  begin
+    SVGStyleRadGradFiller := TSVGRadialGradientPolygonFiller.Create(FGradientLUT);
+    try
+      SVGStyleRadGradFiller.EllipseBounds := DpiAwareFloatRect(100, 265, 300, 385);
+      SVGStyleRadGradFiller.FocalPoint := FloatPoint(FRadialOrigin);
+      PolygonFS(ImgView32.Bitmap, PolygonBottom, SVGStyleRadGradFiller);
+    finally
+      SVGStyleRadGradFiller.Free;
+    end;
+  end;
+  PolylineFS(ImgView32.Bitmap, PolygonBottom, ClBlack32, True, 1);
+
+  //draw some text ...
+  PolyPolygonFS(ImgView32.Bitmap, FTextNotesPoly, clBlack32);
+  PolyPolygonFS(ImgView32.Bitmap, FTextTopPoly, clBlack32);
+  PolyPolygonFS(ImgView32.Bitmap, FTextBottomPoly, clBlack32);
+
+  with ImgView32.Bitmap do
+  begin
+    Draw(FLinearStart.X - FKnobRadius, FLinearStart.Y - FKnobRadius, FKnobBitmap);
+    Draw(FLinearEnd.X - FKnobRadius, FLinearEnd.Y - FKnobRadius, FKnobBitmap);
+    Draw(FRadialOrigin.X - FKnobRadius, FRadialOrigin.Y - FKnobRadius, FKnobBitmap);
+    if RgpEllipseFillStyle.ItemIndex = SimpleStyle then
+    begin
+      Draw(FRadialX.X - FKnobRadius, FRadialX.Y - FKnobRadius, FKnobBitmap);
+      Draw(FRadialY.X - FKnobRadius, FRadialY.Y - FKnobRadius, FKnobBitmap);
+    end;
+  end;
+end;
+
+procedure TMainForm.BtnDefaultsClick(Sender: TObject);
+begin
+  with MemoColorStops do
+  begin
+    Clear;
+    Lines.BeginUpdate;
+    Lines.Add('0.0: clRed32');
+    Lines.Add('0.1: clYellow32');
+    Lines.Add('0.3: clLime32');
+    Lines.Add('0.5: $AA00FFFF');
+    Lines.Add('0.7: clBlue32');
+    Lines.Add('0.9: clFuchsia32');
+    Lines.Add('1.0: $80FF0000');
+    Lines.EndUpdate;
+  end;
+end;
+
+procedure TMainForm.BtnExitClick(Sender: TObject);
+begin
+  Close;
+end;
+
+procedure TMainForm.CmbLUTChange(Sender: TObject);
+begin
+  case CmbLUT.ItemIndex of
+    0: MnuOrder4.Checked := True;
+    1: MnuOrder5.Checked := True;
+    2: MnuOrder6.Checked := True;
+    3: MnuOrder7.Checked := True;
+    4: MnuOrder8.Checked := True;
+    5: MnuOrder9.Checked := True;
+    6: MnuOrder10.Checked := True;
+    7: MnuOrder11.Checked := True;
+    8: MnuOrder12.Checked := True;
+    9: MnuOrder13.Checked := True;
+  end;
+  FGradientLUT.Order := 4 + CmbLUT.ItemIndex;
+end;
+
+procedure TMainForm.MemoColorStopsChange(Sender: TObject);
+begin
+  StrToArrayColor32Gradient(MemoColorStops.Lines, FGradient);
+  FGradient.FillColorLookUpTable(FGradientLUT);
+
+  DrawImage;
+end;
+
+procedure TMainForm.MnuFileOpenClick(Sender: TObject);
+begin
+  if OpenDialog.Execute then
+    MemoColorStops.Lines.LoadFromFile(OpenDialog.FileName);
+end;
+
+procedure TMainForm.MnuFileSaveAsClick(Sender: TObject);
+begin
+  if SaveDialog.Execute then
+    MemoColorStops.Lines.SaveToFile(SaveDialog.FileName);
+end;
+
+procedure TMainForm.MnuOrderClick(Sender: TObject);
+begin
+  CmbLUT.ItemIndex := TMenuItem(Sender).Tag;
+  TMenuItem(Sender).Checked := True;
+  FGradientLUT.Order := 4 + CmbLUT.ItemIndex;
+end;
+
+procedure TMainForm.MnuRadialFillStyleClick(Sender: TObject);
+begin
+  RgpEllipseFillStyle.ItemIndex := TMenuItem(Sender).Tag;
+  TMenuItem(Sender).Checked := True;
+  DrawImage;
+end;
+
+procedure TMainForm.MnuSpreadClick(Sender: TObject);
+begin
+  RgpWrapMode.ItemIndex := TMenuItem(Sender).Tag;
+  TMenuItem(Sender).Checked := True;
+  DrawImage;
+end;
+
+procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char);
+begin
+  if Key = #27 then
+    Close;
+end;
+
+procedure TMainForm.RgpEllipseFillStyleClick(Sender: TObject);
+begin
+  case RgpEllipseFillStyle.ItemIndex of
+    0: MnuSimple.Checked := True;
+    1: MnuSVG.Checked := True;
+  end;
+  DrawImage;
+end;
+
+procedure TMainForm.RgpWrapModeClick(Sender: TObject);
+begin
+  case RgpWrapMode.ItemIndex of
+    0: MnuClamp.Checked := True;
+    1: MnuRepeat.Checked := True;
+    2: MnuMirror.Checked := True;
+    3: MnuReflect.Checked := True;
+  end;
+  DrawImage;
+end;
+
+procedure TMainForm.LUTOrderChangedHandler(Sender: TObject);
+begin
+  FGradient.FillColorLookUpTable(FGradientLUT);
+  DrawImage;
+end;
+
+initialization
+  SetGamma(1);
+
+end.

+ 2 - 0
Externals/Graphics32/Examples/Drawing/GradFills/Media.rc

@@ -0,0 +1,2 @@
+MainIcon ICON "../../Media/GR32.ico"
+GRAPHICS32_CRV RCDATA "../../Media/GRAPHICS32.crv"

+ 744 - 0
Externals/Graphics32/Examples/Drawing/GradLines/GradLines.cbproj

@@ -0,0 +1,744 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{35844EF1-92E1-454C-823C-6FDB54020649}</ProjectGuid>
+        <ProjectVersion>18.6</ProjectVersion>
+        <FrameworkType>VCL</FrameworkType>
+        <AppType>Application</AppType>
+        <MainSource>GradLines.cpp</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>3</TargetedPlatforms>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+        <DynamicRTL>true</DynamicRTL>
+        <UsePackages>true</UsePackages>
+        <IntermediateOutputDir>lib</IntermediateOutputDir>
+        <FinalOutputDir>bin</FinalOutputDir>
+        <BCC_wpar>false</BCC_wpar>
+        <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
+        <BCC_ExtendedErrorInfo>true</BCC_ExtendedErrorInfo>
+        <ILINK_TranslatedLibraryPath>$(BDSLIB)\$(PLATFORM)\release\$(LANGDIR);$(ILINK_TranslatedLibraryPath)</ILINK_TranslatedLibraryPath>
+        <ProjectType>CppVCLApplication</ProjectType>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
+        <AllPackageLibs>rtl.lib;vcl.lib;GR32_R.lib</AllPackageLibs>
+        <_TCHARMapping>wchar_t</_TCHARMapping>
+        <Multithreaded>true</Multithreaded>
+        <Icon_MainIcon>$(BDS)\bin\cbuilder_PROJECTICON.ico</Icon_MainIcon>
+        <UWP_CppLogo44>$(BDS)\bin\Artwork\Windows\UWP\cppreg_UwpDefault_44.png</UWP_CppLogo44>
+        <UWP_CppLogo150>$(BDS)\bin\Artwork\Windows\UWP\cppreg_UwpDefault_150.png</UWP_CppLogo150>
+        <IncludePath>$(IncludePath)</IncludePath>
+        <ILINK_LibraryPath>$(ILINK_LibraryPath)</ILINK_LibraryPath>
+        <SanitizedProjectName>GradLines</SanitizedProjectName>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <DCC_HppOutputARM>true</DCC_HppOutputARM>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <PackageImports>adortl;appanalytics;bcbie;bcbsmp;bindcomp;bindcompdbx;bindcompfmx;bindcompvcl;bindengine;CloudService;CustomIPTransport;DataSnapClient;DataSnapCommon;DataSnapConnectors;DatasnapConnectorsFreePascal;DataSnapFireDAC;DataSnapIndy10ServerTransport;DataSnapNativeClient;DataSnapProviderClient;DataSnapServer;DataSnapServerMidas;dbexpress;dbrtl;dbxcds;DbxClientDriver;DbxCommonDriver;DBXDb2Driver;DBXFirebirdDriver;DBXInformixDriver;DBXInterBaseDriver;DBXMSSQLDriver;DBXMySQLDriver;DBXOdbcDriver;DBXOracleDriver;DBXSqliteDriver;DBXSybaseASADriver;DBXSybaseASEDriver;dsnap;dsnapcon;dsnapxml;emsclient;emsclientfiredac;emsedge;emshosting;emsserverresource;FireDAC;FireDACADSDriver;FireDACASADriver;FireDACCommon;FireDACCommonDriver;FireDACCommonODBC;FireDACDb2Driver;FireDACDBXDriver;FireDACDSDriver;FireDACIBDriver;FireDACInfxDriver;FireDACMongoDBDriver;FireDACMSAccDriver;FireDACMSSQLDriver;FireDACMySQLDriver;FireDACODBCDriver;FireDACOracleDriver;FireDACPgDriver;FireDACSqliteDriver;FireDACTDataDriver;fmx;fmxase;fmxdae;fmxFireDAC;fmxobj;FMXTee;FmxTeeUI;GR32_D;GR32_R;IndyCore;IndyIPClient;IndyIPCommon;IndyIPServer;IndyProtocols;IndySystem;inet;inetdb;inetdbxpress;RESTBackendComponents;RESTComponents;rtl;soapmidas;soaprtl;soapserver;svn;SynEdit_BCB;Tee;TeeDB;TeeUI;tethering;vcl;vclactnband;vcldb;vcldsnap;vclFireDAC;vclie;vclimg;VCLRESTComponents;VclSmp;vcltouch;vclwinx;vclx;xmlrtl;$(PackageImports)</PackageImports>
+        <IncludePath>$(BDSINCLUDE)\windows\vcl;$(IncludePath)</IncludePath>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <PackageImports>adortl;appanalytics;bcbie;bcbsmp;bindcomp;bindcompdbx;bindcompfmx;bindcompvcl;bindengine;CloudService;CustomIPTransport;DataSnapClient;DataSnapCommon;DataSnapConnectors;DatasnapConnectorsFreePascal;DataSnapFireDAC;DataSnapIndy10ServerTransport;DataSnapNativeClient;DataSnapProviderClient;DataSnapServer;DataSnapServerMidas;dbexpress;dbrtl;dbxcds;DbxClientDriver;DbxCommonDriver;DBXDb2Driver;DBXFirebirdDriver;DBXInformixDriver;DBXInterBaseDriver;DBXMSSQLDriver;DBXMySQLDriver;DBXOdbcDriver;DBXOracleDriver;DBXSqliteDriver;DBXSybaseASADriver;DBXSybaseASEDriver;dsnap;dsnapcon;dsnapxml;emsclient;emsclientfiredac;emsedge;emshosting;emsserverresource;FireDAC;FireDACADSDriver;FireDACASADriver;FireDACCommon;FireDACCommonDriver;FireDACCommonODBC;FireDACDb2Driver;FireDACDBXDriver;FireDACDSDriver;FireDACIBDriver;FireDACInfxDriver;FireDACMongoDBDriver;FireDACMSAccDriver;FireDACMSSQLDriver;FireDACMySQLDriver;FireDACODBCDriver;FireDACOracleDriver;FireDACPgDriver;FireDACSqliteDriver;FireDACTDataDriver;fmx;fmxase;fmxdae;fmxFireDAC;fmxobj;FMXTee;FmxTeeUI;GR32_R;IndyCore;IndyIPClient;IndyIPCommon;IndyIPServer;IndyProtocols;IndySystem;inet;inetdb;inetdbxpress;RESTBackendComponents;RESTComponents;rtl;soapmidas;soaprtl;soapserver;Tee;TeeDB;TeeUI;tethering;vcl;vclactnband;vcldb;vcldsnap;vclFireDAC;vclie;vclimg;VCLRESTComponents;VclSmp;vcltouch;vclwinx;vclx;xmlrtl;$(PackageImports)</PackageImports>
+        <IncludePath>$(BDSINCLUDE)\windows\vcl;$(IncludePath)</IncludePath>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
+        <BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <Defines>_DEBUG;$(Defines)</Defines>
+        <BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
+        <BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
+        <DCC_Define>DEBUG</DCC_Define>
+        <BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
+        <TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
+        <BCC_StackFrames>true</BCC_StackFrames>
+        <ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
+        <TASM_Debugging>Full</TASM_Debugging>
+        <BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
+        <BCC_EnableCPPExceptions>true</BCC_EnableCPPExceptions>
+        <BCC_DisableFramePtrElimOpt>true</BCC_DisableFramePtrElimOpt>
+        <BCC_DisableSpellChecking>true</BCC_DisableSpellChecking>
+        <CLANG_UnwindTables>true</CLANG_UnwindTables>
+        <ILINK_LibraryPath>$(BDSLIB)\$(PLATFORM)\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+        <ILINK_TranslatedLibraryPath>$(BDSLIB)\$(PLATFORM)\debug\$(LANGDIR);$(ILINK_TranslatedLibraryPath)</ILINK_TranslatedLibraryPath>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+        <BCC_UseClassicCompiler>false</BCC_UseClassicCompiler>
+        <LinkPackageImports>rtl.bpi;vcl.bpi;GR32_R.bpi</LinkPackageImports>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+        <LinkPackageImports>rtl.bpi;vcl.bpi;GR32_R.bpi</LinkPackageImports>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <Defines>NDEBUG;$(Defines)</Defines>
+        <TASM_Debugging>None</TASM_Debugging>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+        <BCC_UseClassicCompiler>false</BCC_UseClassicCompiler>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+    </PropertyGroup>
+    <ItemGroup>
+        <CppCompile Include="GradLines.cpp">
+            <BuildOrder>0</BuildOrder>
+        </CppCompile>
+        <DelphiCompile Include="MainUnit.pas">
+            <BuildOrder>2</BuildOrder>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>CPlusPlusBuilder.Personality.12</Borland.Personality>
+        <Borland.ProjectType>CppVCLApplication</Borland.ProjectType>
+        <BorlandProject>
+            <CPlusPlusBuilder.Personality>
+                <ProjectProperties>
+                    <ProjectProperties Name="AutoShowDeps">False</ProjectProperties>
+                    <ProjectProperties Name="ManagePaths">True</ProjectProperties>
+                    <ProjectProperties Name="VerifyPackages">True</ProjectProperties>
+                    <ProjectProperties Name="IndexFiles">False</ProjectProperties>
+                </ProjectProperties>
+                <Source>
+                    <Source Name="MainSource">GradLines.cpp</Source>
+                </Source>
+                <Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcboffice2k260.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcbofficexp260.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
+                </Excluded_Packages>
+            </CPlusPlusBuilder.Personality>
+            <Deployment Version="3">
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\bin\cc32c260.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx32\libcgcrtl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx64\libcgstl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\bin\cc32260mt.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\bin\cc32260.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx32\libcgstl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(UsingDelphiRTL)'=='true'" LocalName="$(BDS)\bin\borlndmm.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(UsingDelphiRTL)'=='true'" LocalName="$(BDS)\bin64\borlndmm.dll" Class="DependencyModule">
+                    <Platform Name="Win64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\bin64\cc64260mt.dll" Class="DependencyModule">
+                    <Platform Name="Win64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="..\..\..\Binaries\Win32\Debug\GradLines.tds" Configuration="Debug" Class="DebugSymbols">
+                    <Platform Name="Win32">
+                        <RemoteName>GradLines.tds</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="..\..\..\Binaries\Win32\Debug\GradLines.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>GradLines.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\bin64\cc64260.dll" Class="DependencyModule">
+                    <Platform Name="Win64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\bin\cc32c260mt.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx64\libcgcrtl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1536">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2048">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch768">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_CppLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_CppLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Cpp.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Cpp.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

+ 34 - 0
Externals/Graphics32/Examples/Drawing/GradLines/GradLines.cpp

@@ -0,0 +1,34 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("GradLines.res");
+USEFORMNS("MainUnit.pas", Mainunit, FormGradientLines);
+//---------------------------------------------------------------------------
+int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
+{
+	try
+	{
+		Application->Initialize();
+		Application->MainFormOnTaskBar = true;
+		Application->CreateForm(__classid(TFormGradientLines), &FormGradientLines);
+		Application->Run();
+	}
+	catch (Exception &exception)
+	{
+		Application->ShowException(&exception);
+	}
+	catch (...)
+	{
+		try
+		{
+			throw Exception("");
+		}
+		catch (Exception &exception)
+		{
+			Application->ShowException(&exception);
+		}
+	}
+	return 0;
+}
+//---------------------------------------------------------------------------

+ 13 - 0
Externals/Graphics32/Examples/Drawing/GradLines/GradLines.dpr

@@ -0,0 +1,13 @@
+program GradLines;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFormGradientLines, FormGradientLines);
+  Application.Run;
+end.

+ 167 - 0
Externals/Graphics32/Examples/Drawing/GradLines/GradLines.dproj

@@ -0,0 +1,167 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>GradLines.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{87de5d8d-9ccb-4069-abd6-fe822b52f62c}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">GradLines</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>GradLines</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">GradLines.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 162 - 0
Externals/Graphics32/Examples/Drawing/GradLines/MainUnit.dfm

@@ -0,0 +1,162 @@
+object FormGradientLines: TFormGradientLines
+  Left = 220
+  Top = 105
+  Caption = 'Gradient Lines Example'
+  ClientHeight = 423
+  ClientWidth = 623
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  KeyPreview = True
+  Position = poScreenCenter
+  OnCreate = FormCreate
+  OnKeyDown = FormKeyDown
+  DesignSize = (
+    623
+    423)
+  TextHeight = 13
+  object LblTotal: TLabel
+    Left = 510
+    Top = 92
+    Width = 28
+    Height = 13
+    Anchors = [akTop, akRight]
+    Caption = 'Total:'
+  end
+  object PaintBox: TPaintBox32
+    Left = 8
+    Top = 8
+    Width = 496
+    Height = 409
+    Anchors = [akLeft, akTop, akRight, akBottom]
+    TabOrder = 0
+  end
+  object BtnAddOne: TButton
+    Left = 510
+    Top = 8
+    Width = 105
+    Height = 21
+    Anchors = [akTop, akRight]
+    Caption = 'Add One'
+    TabOrder = 1
+    OnClick = BtnAddOneClick
+  end
+  object BtnAddTen: TButton
+    Left = 510
+    Top = 34
+    Width = 105
+    Height = 21
+    Anchors = [akTop, akRight]
+    Caption = 'Add Ten'
+    TabOrder = 2
+    OnClick = BtnAddTenClick
+  end
+  object BtnClear: TButton
+    Left = 510
+    Top = 60
+    Width = 105
+    Height = 21
+    Anchors = [akTop, akRight]
+    Caption = 'Clear'
+    TabOrder = 3
+    OnClick = BtnClearClick
+  end
+  object RgpFade: TRadioGroup
+    Left = 510
+    Top = 224
+    Width = 105
+    Height = 89
+    Anchors = [akTop, akRight]
+    Caption = 'Fade'
+    Ctl3D = True
+    ItemIndex = 0
+    Items.Strings = (
+      'None'
+      'Slow'
+      'Fast')
+    ParentCtl3D = False
+    TabOrder = 4
+    OnClick = RgpFadeClick
+  end
+  object RgpDraw: TRadioGroup
+    Left = 510
+    Top = 136
+    Width = 105
+    Height = 81
+    Anchors = [akTop, akRight]
+    Caption = 'Draw'
+    Ctl3D = True
+    ItemIndex = 0
+    Items.Strings = (
+      'Slow'
+      'Normal'
+      'Fast')
+    ParentCtl3D = False
+    TabOrder = 5
+    OnClick = RgpDrawClick
+  end
+  object PnlTotalLines: TPanel
+    Left = 511
+    Top = 108
+    Width = 104
+    Height = 17
+    Anchors = [akTop, akRight]
+    BevelOuter = bvNone
+    BorderStyle = bsSingle
+    Caption = '0'
+    Color = clWindow
+    Ctl3D = False
+    ParentCtl3D = False
+    TabOrder = 6
+  end
+  object RepaintOpt: TCheckBox
+    Left = 510
+    Top = 320
+    Width = 105
+    Height = 17
+    Anchors = [akTop, akRight]
+    Caption = 'Repaint Optimization'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -9
+    Font.Name = 'Tahoma'
+    Font.Style = []
+    ParentFont = False
+    TabOrder = 7
+    OnClick = RepaintOptClick
+  end
+  object Memo: TMemo
+    Left = 510
+    Top = 343
+    Width = 105
+    Height = 74
+    TabStop = False
+    Anchors = [akTop, akRight]
+    Color = clInfoBk
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -9
+    Font.Name = 'Tahoma'
+    Font.Style = []
+    Lines.Strings = (
+      'Disable fading to see '
+      'effect of repaint '
+      'optimization.'
+      ''
+      '(Maximize application'
+      'on modern CPUs)')
+    ParentFont = False
+    ReadOnly = True
+    TabOrder = 8
+  end
+  object TimerFrameRate: TTimer
+    Enabled = False
+    Interval = 5000
+    OnTimer = TimerFrameRateTimer
+    Left = 304
+    Top = 216
+  end
+end

+ 155 - 0
Externals/Graphics32/Examples/Drawing/GradLines/MainUnit.lfm

@@ -0,0 +1,155 @@
+object FormGradientLines: TFormGradientLines
+  Left = 220
+  Top = 105
+  Caption = 'Gradient Lines Example'
+  ClientHeight = 423
+  ClientWidth = 623
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poScreenCenter
+  OnCreate = FormCreate
+  DesignSize = (
+    623
+    423)
+  PixelsPerInch = 96
+  TextHeight = 13
+  object LblTotal: TLabel
+    Left = 510
+    Top = 92
+    Width = 28
+    Height = 13
+    Anchors = [akTop, akRight]
+    Caption = 'Total:'
+  end
+  object PaintBox: TPaintBox32
+    Left = 8
+    Top = 8
+    Width = 496
+    Height = 409
+    Anchors = [akLeft, akTop, akRight, akBottom]
+    TabOrder = 0
+  end
+  object BtnAddOne: TButton
+    Left = 510
+    Top = 8
+    Width = 105
+    Height = 21
+    Anchors = [akTop, akRight]
+    Caption = 'Add One'
+    TabOrder = 1
+    OnClick = BtnAddOneClick
+  end
+  object BtnAddTen: TButton
+    Left = 510
+    Top = 34
+    Width = 105
+    Height = 21
+    Anchors = [akTop, akRight]
+    Caption = 'Add Ten'
+    TabOrder = 2
+    OnClick = BtnAddTenClick
+  end
+  object BtnClear: TButton
+    Left = 510
+    Top = 60
+    Width = 105
+    Height = 21
+    Anchors = [akTop, akRight]
+    Caption = 'Clear'
+    TabOrder = 3
+    OnClick = BtnClearClick
+  end
+  object RgpFade: TRadioGroup
+    Left = 510
+    Top = 224
+    Width = 105
+    Height = 89
+    Anchors = [akTop, akRight]
+    Caption = 'Fade'
+    Ctl3D = True
+    ItemIndex = 0
+    Items.Strings = (
+      'None'
+      'Slow'
+      'Fast')
+    ParentCtl3D = False
+    TabOrder = 4
+    OnClick = RgpFadeClick
+  end
+  object RgpDraw: TRadioGroup
+    Left = 510
+    Top = 136
+    Width = 105
+    Height = 81
+    Anchors = [akTop, akRight]
+    Caption = 'Draw'
+    Ctl3D = True
+    ItemIndex = 0
+    Items.Strings = (
+      'Slow'
+      'Normal'
+      'Fast')
+    ParentCtl3D = False
+    TabOrder = 5
+    OnClick = RgpDrawClick
+  end
+  object PnlTotalLines: TPanel
+    Left = 511
+    Top = 108
+    Width = 104
+    Height = 17
+    Anchors = [akTop, akRight]
+    BevelOuter = bvNone
+    BorderStyle = bsSingle
+    Caption = '0'
+    Color = clWindow
+    Ctl3D = False
+    ParentCtl3D = False
+    TabOrder = 6
+  end
+  object RepaintOpt: TCheckBox
+    Left = 510
+    Top = 320
+    Width = 105
+    Height = 17
+    Anchors = [akTop, akRight]
+    Caption = 'Repaint Optimization'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -9
+    Font.Name = 'Tahoma'
+    Font.Style = []
+    ParentFont = False
+    TabOrder = 7
+    OnClick = RepaintOptClick
+  end
+  object Memo: TMemo
+    Left = 510
+    Top = 343
+    Width = 105
+    Height = 74
+    TabStop = False
+    Anchors = [akTop, akRight]
+    Color = clInfoBk
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -9
+    Font.Name = 'Tahoma'
+    Font.Style = []
+    Lines.Strings = (
+      'Disable fading to see '
+      'effect of repaint '
+      'optimization.'
+      ''
+      '(Maximize application'
+      'on modern CPUs)')
+    ParentFont = False
+    ReadOnly = True
+    TabOrder = 8
+  end
+end

+ 428 - 0
Externals/Graphics32/Examples/Drawing/GradLines/MainUnit.pas

@@ -0,0 +1,428 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is Gradient Lines Example
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+{-$define FADE_BLEND}
+
+uses
+  {$IFDEF FPC} LCLIntf, LResources, Buttons, {$ENDIF} SysUtils, Classes, 
+  Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Types,
+  GR32,
+  GR32_Blend,
+  GR32_Image,
+  GR32_System,
+  GR32_LowLevel;
+
+type
+  TVector2f = record
+    X, Y: Single;
+  end;
+
+  TLine = class
+  public
+    Bitmap: TBitmap32;
+    P1, P2: TVector2f;     // positions
+    V1, V2: TVector2f;     // velocities
+    C1, C2, C3: TColor32;  // colors that define gradient pattern
+    t1, t2, t3: Single;
+    MaxVelocity: Single;
+    constructor Create(ABitmap: TBitmap32);
+    procedure Advance(DeltaT: Single);
+    function GetLength: Single;
+    procedure Paint;
+  end;
+
+  { TFormGradientLines }
+
+  TFormGradientLines = class(TForm)
+    BtnAddOne: TButton;
+    BtnAddTen: TButton;
+    BtnClear: TButton;
+    LblTotal: TLabel;
+    Memo: TMemo;
+    PaintBox: TPaintBox32;
+    PnlTotalLines: TPanel;
+    RgpDraw: TRadioGroup;
+    RgpFade: TRadioGroup;
+    RepaintOpt: TCheckBox;
+    TimerFrameRate: TTimer;
+    procedure FormCreate(Sender: TObject);
+    procedure RepaintOptClick(Sender: TObject);
+    procedure BtnAddOneClick(Sender: TObject);
+    procedure BtnAddTenClick(Sender: TObject);
+    procedure BtnClearClick(Sender: TObject);
+    procedure RgpFadeClick(Sender: TObject);
+    procedure RgpDrawClick(Sender: TObject);
+    procedure TimerFrameRateTimer(Sender: TObject);
+    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+  protected
+    FBenchMark: boolean;
+    FBenchMarkCounter: integer;
+    Lines: array of TLine;
+    FadeCount: Integer;
+    Pass: Integer;
+    DrawPasses: Integer;
+    FrameCount: integer;
+    FStopwatch: TStopwatch;
+    procedure AppEventsIdle(Sender: TObject; var Done: Boolean);
+    procedure StartBenchmark;
+  public
+    procedure AddLine;
+    procedure AddLines(N: Integer);
+  end;
+
+var
+  FormGradientLines: TFormGradientLines;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Math,
+  Windows;
+
+function VectorAdd(const A, B: TVector2f): TVector2f;
+begin
+  Result.X := A.X + B.X;
+  Result.Y := A.Y + B.Y;
+end;
+
+function VectorSub(const A, B: TVector2f): TVector2f;
+begin
+  Result.X := A.X - B.X;
+  Result.Y := A.Y - B.Y;
+end;
+
+function VectorLen(const A: TVector2f): Single;
+begin
+  Result := SqRt(SqR(A.X) + SqR(A.Y));
+end;
+
+function VectorDot(const A, B: TVector2f): Single;
+begin
+  Result := A.X * B.X + A.Y * B.Y;
+end;
+
+function VectorScale(const A: TVector2f; Factor: Single): TVector2f;
+begin
+  Result.X := A.X * Factor;
+  Result.Y := A.Y * Factor;
+end;
+
+{ TLine }
+
+constructor TLine.Create(ABitmap: TBitmap32);
+begin
+  Bitmap := ABitmap;
+  MaxVelocity := 1;
+end;
+
+procedure TLine.Advance(DeltaT: Single);
+const
+  COne400 : Single = 1 / 400;
+  COne300 : Single = 1 / 300;
+
+  procedure AdvancePoint(var P, V: TVector2f; t: Single);
+  begin
+    { apply velocities }
+    P := VectorAdd(P, VectorScale(V, t));
+
+    { reflect from walls }
+    if P.X < 0 then
+    begin
+      P.X := 0;
+      V.X := -V.X;
+    end;
+    if P.X >= FormGradientLines.PaintBox.Width then
+    begin
+      P.X := FormGradientLines.PaintBox.Width - 1;
+      V.X := - V.X;
+    end;
+    if P.Y < 0 then
+    begin
+      P.Y := 0;
+      V.Y := -V.Y;
+    end;
+    if P.Y >= FormGradientLines.PaintBox.Height then
+    begin
+      P.Y := FormGradientLines.PaintBox.Height - 1;
+      V.Y := - V.Y
+    end;
+
+    { change velocity a little bit }
+    V.X := V.X + t * (Random - 0.5) * 0.25;
+    V.Y := V.Y + t * (Random - 0.5) * 0.25;
+
+    { limit velocity }
+    if VectorLen(V) > MaxVelocity then
+      V := VectorScale(V, 1 / VectorLen(V));
+  end;
+
+begin
+  AdvancePoint(P1, V1, DeltaT);
+  AdvancePoint(P2, V2, DeltaT);
+
+  C1 := HSLtoRGB(t1, Sin(t1 * 0.55) * 0.4 + 0.6, 0.5);
+  C1 := SetAlpha(C1, Round(Sin(t1) * 25 + 50));
+  t1 := t1 + Random * COne300;
+
+  C2 := HSLtoRGB(t2, Sin(t2 * 0.55) * 0.4 + 0.6, 0.5);
+  C2 := SetAlpha(C2, Round(Sin(t2) * 25 + 50));
+  t2 := t2 + Random * COne400;
+
+  C3 := HSLtoRGB(t3, Sin(t3 * 0.55) * 0.4 + 0.6, 0.5);
+  C3 := SetAlpha(C3, Round(Sin(t3) * 25 + 50));
+  t3 := t3 + Random * COne400;
+end;
+
+function TLine.GetLength: Single;
+begin
+  Result := VectorLen(VectorSub(P1, P2));
+end;
+
+procedure TLine.Paint;
+var
+  L: Single;
+begin
+  // this shows how to draw a gradient line
+  L := GetLength;
+  if L < 1 then Exit;
+  Bitmap.SetStipple([C1, C2, C3]);
+  Bitmap.StippleStep := 2 / L; {2 = 3 - 1 = Number of colors in a pattern - 1}
+  Bitmap.StippleCounter := 0;
+  Bitmap.LineFSP(P1.X, P1.Y, P2.X, P2.Y);
+end;
+
+{ TFormGradientLines }
+
+procedure TFormGradientLines.FormCreate(Sender: TObject);
+begin
+  FadeCount := 0;
+  DrawPasses := 2;
+  Application.OnIdle := AppEventsIdle;
+
+  if (FindCmdLineSwitch('benchmark')) then
+    StartBenchmark;
+end;
+
+procedure TFormGradientLines.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+  if (Key <> VK_F1) then
+    exit;
+  Key := 0;
+
+  StartBenchmark;
+end;
+
+procedure TFormGradientLines.AddLine;
+var
+  L: TLine;
+begin
+  SetLength(Lines, Length(Lines) + 1);
+  L := TLine.Create(PaintBox.Buffer);
+  Lines[High(Lines)] := L;
+  L.t1 := Random * 3;
+  L.t2 := Random * 3;
+  L.t3 := Random * 3;
+  L.P1.X := Random(PaintBox.Buffer.Width div 2 - 1);
+  L.P2.X := Random(PaintBox.Buffer.Width div 2 - 1);
+  L.P1.Y := Random(PaintBox.Buffer.Height div 2 - 1);
+  L.P2.Y := Random(PaintBox.Buffer.Height div 2 - 1);
+  PnlTotalLines.Caption := IntToStr(Length(Lines));
+end;
+
+procedure TFormGradientLines.AddLines(N: Integer);
+var
+  Index: Integer;
+begin
+  for Index := 0 to N - 1 do
+    AddLine;
+end;
+
+procedure TFormGradientLines.AppEventsIdle(Sender: TObject; var Done: Boolean);
+var
+  I, J: Integer;
+begin
+  // We need to be continously called. Even when there are no
+  // messages in the message queue. Otherwise the framerate calculation will
+  // not work.
+
+  Done := False;
+
+  if (Length(Lines) = 0) then
+    exit;
+
+  PaintBox.BeginUpdate;
+  try
+    for J := 0 to DrawPasses - 1 do
+      for I := 0 to High(Lines) do
+      begin
+        Lines[I].Advance(1);
+        Lines[I].Paint;
+      end;
+
+    if FadeCount > 0 then
+    begin
+      if Pass = 0 then
+      begin
+{$ifdef FADE_BLEND}
+        // We fade out the existing image by blending black onto it. The alpha controls how fast we fade.
+        // One problem with this method is that we can't ever fade to complete black due to rounding
+        // errors when working with 8 bit color values.
+        BlendMems($10000000, @PaintBox.Buffer.Bits[0], PaintBox.Buffer.Width * PaintBox.Buffer.Height);
+{$else}
+        // Fade out by scaling the RGB: Faded = Colors * Weight / 255
+        ScaleMems(@PaintBox.Buffer.Bits[0], PaintBox.Buffer.Width * PaintBox.Buffer.Height, $f0);
+{$endif}
+
+        // We're modifying the buffer directly above, so force a complete invalidation.
+        PaintBox.ForceFullInvalidate;
+      end;
+
+      Dec(Pass);
+
+      if (Pass < 0) or (Pass > FadeCount) then
+        Pass := FadeCount;
+    end;
+
+  finally
+    PaintBox.EndUpdate;
+  end;
+  Inc(FrameCount);
+
+  if (FBenchMark) then
+  begin
+    Dec(FBenchMarkCounter);
+    if (FBenchMarkCounter <= 0) then
+      Application.Terminate;
+  end;
+end;
+
+procedure TFormGradientLines.BtnAddOneClick(Sender: TObject);
+begin
+  TimerFrameRate.Enabled := False;
+
+  RandSeed := 0;
+  AddLine;
+
+  FStopwatch := TStopwatch.StartNew;
+  TimerFrameRate.Enabled := True;
+end;
+
+procedure TFormGradientLines.BtnAddTenClick(Sender: TObject);
+begin
+  TimerFrameRate.Enabled := False;
+
+  RandSeed := 0;
+  AddLines(10);
+
+  FStopwatch := TStopwatch.StartNew;
+  TimerFrameRate.Enabled := True;
+end;
+
+procedure TFormGradientLines.BtnClearClick(Sender: TObject);
+var
+  Index: Integer;
+begin
+  for Index := High(Lines) downto 0 do
+    Lines[Index].Free;
+  Lines := nil;
+  PaintBox.Buffer.Clear;
+  PnlTotalLines.Caption := '0';
+  Caption := '';
+  TimerFrameRate.Enabled := False;
+end;
+ 
+procedure TFormGradientLines.RgpFadeClick(Sender: TObject);
+const
+  FC: array [0..2] of Integer = (0, 20, 1);
+begin
+  FadeCount := FC[RgpFade.ItemIndex];
+  RepaintOpt.Enabled := (FadeCount <> 1);
+end;
+
+procedure TFormGradientLines.StartBenchmark;
+begin
+  FBenchMark := True;
+  FBenchMarkCounter := 100*1000;
+
+  WindowState := wsMaximized;
+  RgpDraw.ItemIndex := 2; // Fast draw
+  RgpFade.ItemIndex := 0; // No fade
+  RepaintOpt.Checked := True; // Repaint optimizer
+
+  BtnAddTen.Click;
+end;
+
+procedure TFormGradientLines.TimerFrameRateTimer(Sender: TObject);
+var
+  FPS: Single;
+begin
+  FStopwatch.Stop;
+
+  TTimer(Sender).Enabled := False;
+
+  if (FStopwatch.ElapsedMilliseconds <> 0) then
+    FPS := 1000 * FrameCount / FStopwatch.ElapsedMilliseconds
+  else
+    FPS := 0;
+
+  if (FBenchMark) then
+    Caption := Format('%.0n fps (%.0n)', [FPS, 1.0 * FBenchMarkCounter])
+  else
+    Caption := Format('%.0n fps', [FPS]);
+
+  FrameCount := 0;
+  TTimer(Sender).Enabled := True;
+  FStopwatch := TStopwatch.StartNew;
+end;
+
+procedure TFormGradientLines.RgpDrawClick(Sender: TObject);
+begin
+  DrawPasses := (RgpDraw.ItemIndex + 1) * 3 - 2;
+end;
+
+procedure TFormGradientLines.RepaintOptClick(Sender: TObject);
+begin
+  if RepaintOpt.Checked then
+    PaintBox.RepaintMode := rmOptimizer
+  else
+    PaintBox.RepaintMode := rmFull;
+end;
+
+end.

+ 1 - 0
Externals/Graphics32/Examples/Drawing/GradLines/Media.rc

@@ -0,0 +1 @@
+MainIcon ICON "../../Media/GR32.ico"

+ 53 - 0
Externals/Graphics32/Examples/Drawing/GradLines/createbundle.sh

@@ -0,0 +1,53 @@
+#!/bin/sh
+# Force Bourne shell in case tcsh is default.
+#
+appname=GradLines
+appfolder=$appname.app
+macosfolder=$appfolder/Contents/MacOS
+plistfile=$appfolder/Contents/Info.plist
+appfile=$appname
+#
+if ! [ -e $appfile ]
+then
+  echo "$appfile does not exist"
+elif [ -e $appfolder ]
+then
+  echo "$appfolder already exists"
+else
+  echo "Creating $appfolder..."
+  mkdir $appfolder
+  mkdir $appfolder/Contents
+  mkdir $appfolder/Contents/MacOS
+  mkdir $appfolder/Contents/Resources
+#
+# Instead of copying executable into .app folder after each compile,
+# simply create a symbolic link to executable.
+  ln -s ../../../$appname $macosfolder/$appname
+# Also create a symbolic link for the resource files
+  ln -s ../../../../../../Media $appfolder/Contents/Resources/Media
+#
+# Create PkgInfo file.
+  echo "APPL????" >$appfolder/Contents/PkgInfo
+#
+# Create information property list file (Info.plist).
+  echo '<?xml version="1.0" encoding="UTF-8"?>' >$plistfile
+  echo '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >>$plistfile
+  echo '<plist version="1.0">' >>$plistfile
+  echo '<dict>' >>$plistfile
+  echo '  <key>CFBundleDevelopmentRegion</key>' >>$plistfile
+  echo '  <string>English</string>' >>$plistfile
+  echo '  <key>CFBundleExecutable</key>' >>$plistfile
+  echo '  <string>'$appname'</string>' >>$plistfile
+  echo '  <key>CFBundleInfoDictionaryVersion</key>' >>$plistfile
+  echo '  <string>6.0</string>' >>$plistfile
+  echo '  <key>CFBundlePackageType</key>' >>$plistfile
+  echo '  <string>APPL</string>' >>$plistfile
+  echo '  <key>CFBundleSignature</key>' >>$plistfile
+  echo '  <string>????</string>' >>$plistfile
+  echo '  <key>CFBundleVersion</key>' >>$plistfile
+  echo '  <string>1.0</string>' >>$plistfile
+  echo '  <key>CSResourcesFileMapped</key>' >>$plistfile
+  echo '  <true/>' >>$plistfile
+  echo '</dict>' >>$plistfile
+  echo '</plist>' >>$plistfile
+fi

+ 13 - 0
Externals/Graphics32/Examples/Drawing/GradSampler/GradSampler.dpr

@@ -0,0 +1,13 @@
+program GradSampler;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas' {FrmGradientSampler};
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFrmGradientSampler, FrmGradientSampler);
+  Application.Run;
+end.

+ 169 - 0
Externals/Graphics32/Examples/Drawing/GradSampler/GradSampler.dproj

@@ -0,0 +1,169 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>GradSampler.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{31324203-1e49-4bee-9056-7a6064f2c223}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">GradSampler</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>GradSampler</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas">
+            <Form>FrmGradientSampler</Form>
+        </DCCReference>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">GradSampler.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 139 - 0
Externals/Graphics32/Examples/Drawing/GradSampler/MainUnit.dfm

@@ -0,0 +1,139 @@
+object FrmGradientSampler: TFrmGradientSampler
+  Left = 0
+  Top = 0
+  Caption = 'Gradient Sampler'
+  ClientHeight = 400
+  ClientWidth = 400
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = MainMenu
+  OldCreateOrder = False
+  OnCreate = FormCreate
+  OnDestroy = FormDestroy
+  OnKeyDown = FormKeyDown
+  PixelsPerInch = 96
+  TextHeight = 13
+  object PaintBox32: TPaintBox32
+    Left = 0
+    Top = 0
+    Width = 400
+    Height = 400
+    Align = alClient
+    RepaintMode = rmOptimizer
+    TabOrder = 0
+    OnDblClick = PaintBox32DblClick
+    OnMouseDown = PaintBox32MouseDown
+    OnMouseMove = PaintBox32MouseMove
+    OnMouseUp = PaintBox32MouseUp
+    OnPaintBuffer = PaintBox32PaintBuffer
+  end
+  object MainMenu: TMainMenu
+    Left = 88
+    Top = 96
+    object MnuFile: TMenuItem
+      Caption = '&File'
+      object MnuClose: TMenuItem
+        Caption = '&Close'
+        OnClick = MnuCloseClick
+      end
+    end
+    object MnuGradient: TMenuItem
+      Caption = '&Gradient'
+      object MnuGradientRadial: TMenuItem
+        Caption = '&Circular'
+        RadioItem = True
+        OnClick = MnuGradientRadialClick
+      end
+      object MnuGradientConic: TMenuItem
+        Caption = 'C&onic'
+        RadioItem = True
+        OnClick = MnuGradientConicClick
+      end
+      object MnuGradientDiamond: TMenuItem
+        Caption = '&Diamond'
+        Checked = True
+        RadioItem = True
+        OnClick = MnuGradientDiamondClick
+      end
+      object MnuGradientXY: TMenuItem
+        Caption = '&XY'
+        RadioItem = True
+        OnClick = MnuGradientXYClick
+      end
+      object MnuGradientXYSqrt: TMenuItem
+        Caption = 'XY &Sqrt'
+        RadioItem = True
+        OnClick = MnuGradientXYSqrtClick
+      end
+      object MnuGradientLinear: TMenuItem
+        Caption = '&Linear'
+        RadioItem = True
+        OnClick = MnuGradientLinearClick
+      end
+      object MnuGradientCustom: TMenuItem
+        Caption = 'C&ustom'
+        RadioItem = True
+        OnClick = MnuGradientCustomClick
+      end
+    end
+    object MnuWrapMode: TMenuItem
+      Caption = '&Wrap Mode'
+      object MnuWrapModeClamp: TMenuItem
+        Caption = '&Clamp'
+        RadioItem = True
+        OnClick = MnuWrapModeClampClick
+      end
+      object MnuWrapModeRepeat: TMenuItem
+        Caption = '&Repeat'
+        RadioItem = True
+        OnClick = MnuWrapModeRepeatClick
+      end
+      object MnuWrapModeMirror: TMenuItem
+        Caption = '&Mirror'
+        Checked = True
+        RadioItem = True
+        OnClick = MnuWrapModeMirrorClick
+      end
+      object MnuWrapModeReflect: TMenuItem
+        Caption = 'Reflect'
+        RadioItem = True
+        OnClick = MnuWrapModeReflectClick
+      end
+    end
+    object MnuBackground: TMenuItem
+      Caption = '&Background Gradient'
+      object MnuBackgroundGradientTriangular: TMenuItem
+        Caption = '&Triangular'
+        Checked = True
+        RadioItem = True
+        OnClick = MnuBackgroundGradientTriangularClick
+      end
+      object MnuBackgroundGradientShepards: TMenuItem
+        Caption = 'Shepards'
+        RadioItem = True
+        OnClick = MnuBackgroundGradientShepardsClick
+      end
+      object MnuBackgroundGradientCustomIDW: TMenuItem
+        Caption = 'Custom Inverse Distance Weighting Gradient'
+        RadioItem = True
+        OnClick = MnuBackgroundGradientCustomIDWClick
+      end
+      object MnuBackgroundGradientVoronoi: TMenuItem
+        Caption = '&Voronoi Gradient'
+        RadioItem = True
+        OnClick = MnuBackgroundGradientVoronoiClick
+      end
+    end
+  end
+  object Animation: TTimer
+    Enabled = False
+    Interval = 30
+    OnTimer = AnimationTimer
+    Left = 200
+    Top = 96
+  end
+end

+ 642 - 0
Externals/Graphics32/Examples/Drawing/GradSampler/MainUnit.pas

@@ -0,0 +1,642 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is Gradient Sampler Example
+ *
+ * The Initial Developer(s) of the Original Code is:
+ * Christian-W. Budde <[email protected]>
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFDEF FPC} LCLIntf, LResources, Buttons, {$ENDIF} SysUtils, Classes,
+  Graphics, Controls, Forms, Dialogs, Menus, ExtCtrls,
+  GR32, GR32_Image, GR32_ColorGradients;
+
+type
+  TMesh = record
+    Point: TFloatPoint;
+    Velocity: TFloatPoint;
+    Color: TColor32;
+    HueChange: Single;
+  end;
+
+  TFrmGradientSampler = class(TForm)
+    PaintBox32: TPaintBox32;
+    MainMenu: TMainMenu;
+    MnuFile: TMenuItem;
+    MnuClose: TMenuItem;
+    MnuGradient: TMenuItem;
+    MnuGradientRadial: TMenuItem;
+    MnuGradientConic: TMenuItem;
+    MnuGradientDiamond: TMenuItem;
+    MnuGradientXY: TMenuItem;
+    MnuGradientXYSqrt: TMenuItem;
+    MnuGradientLinear: TMenuItem;
+    MnuGradientCustom: TMenuItem;
+    MnuWrapMode: TMenuItem;
+    MnuWrapModeClamp: TMenuItem;
+    MnuWrapModeRepeat: TMenuItem;
+    MnuWrapModeMirror: TMenuItem;
+    Animation: TTimer;
+    MnuBackground: TMenuItem;
+    MnuBackgroundGradientTriangular: TMenuItem;
+    MnuBackgroundGradientVoronoi: TMenuItem;
+    MnuBackgroundGradientShepards: TMenuItem;
+    MnuBackgroundGradientCustomIDW: TMenuItem;
+    MnuWrapModeReflect: TMenuItem;
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+    procedure MnuCloseClick(Sender: TObject);
+    procedure MnuGradientConicClick(Sender: TObject);
+    procedure MnuGradientDiamondClick(Sender: TObject);
+    procedure MnuGradientLinearClick(Sender: TObject);
+    procedure MnuGradientRadialClick(Sender: TObject);
+    procedure MnuGradientXYClick(Sender: TObject);
+    procedure MnuGradientXYSqrtClick(Sender: TObject);
+    procedure MnuGradientCustomClick(Sender: TObject);
+    procedure MnuWrapModeClampClick(Sender: TObject);
+    procedure MnuWrapModeRepeatClick(Sender: TObject);
+    procedure MnuWrapModeMirrorClick(Sender: TObject);
+    procedure MnuWrapModeReflectClick(Sender: TObject);
+    procedure PaintBox32PaintBuffer(Sender: TObject);
+    procedure PaintBox32MouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure PaintBox32MouseMove(Sender: TObject; Shift: TShiftState; X,
+      Y: Integer);
+    procedure PaintBox32MouseUp(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure AnimationTimer(Sender: TObject);
+    procedure PaintBox32DblClick(Sender: TObject);
+    procedure MnuBackgroundGradientVoronoiClick(Sender: TObject);
+    procedure MnuBackgroundGradientTriangularClick(Sender: TObject);
+    procedure MnuBackgroundGradientShepardsClick(Sender: TObject);
+    procedure MnuBackgroundGradientCustomIDWClick(Sender: TObject);
+  private
+    FCenter: TFloatPoint;
+    FWrapMode: TWrapMode;
+    FGradCenter: TFloatPoint;
+    FAngle, FRadius: TFloat;
+    FStarAngle: TFloat;
+    FStarVertices: Integer;
+    FLastPos: TFloatPoint;
+    FOutline: TArrayOfFloatPoint;
+    FStartColor: TColor32;
+    FEndColor: TColor32;
+    FGradientSampler: TCustomGradientSampler;
+    FBackgroundGradientSampler: TCustomSparsePointGradientSampler;
+    FMesh: array of TMesh;
+  public
+    procedure UpdateBackgroundGradientSampler;
+  end;
+
+  TMyGradient = class(TCustomGradientLookUpTableSampler)
+  private
+    FPolygon: PArrayOfFloatPoint;
+    FRadius: TFloat;
+    FScale: TFloat;
+    procedure SetRadius(const Value: TFloat);
+  protected
+    procedure AssignTo(Dest: TPersistent); override;
+    procedure UpdateInternals; override;
+  public
+    constructor Create(WrapMode: TWrapMode = wmMirror); override;
+    function GetSampleFloat(X: Single; Y: Single): TColor32; override;
+
+    property Polygon: PArrayOfFloatPoint read FPolygon write FPolygon;
+    property Radius: TFloat read FRadius write SetRadius;
+  end;
+
+var
+  FrmGradientSampler: TFrmGradientSampler;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Math,
+  Types,
+  GR32_Math,
+  GR32_LowLevel,
+  GR32_Polygons,
+  GR32_Geometry,
+  GR32_VectorUtils;
+
+{ TMyGradient }
+
+constructor TMyGradient.Create(WrapMode: TWrapMode = wmMirror);
+begin
+  inherited;
+  FRadius := 10;
+end;
+
+function TMyGradient.GetSampleFloat(X, Y: Single): TColor32;
+var
+  Pt: TFloatPoint;
+  Index: Integer;
+  Dist, MinDist, MaxDist: TFloat;
+begin
+  Pt := FloatPoint(X, Y);
+  Dist := Distance(Pt, FPolygon^[0]) ;
+  MinDist := Dist;
+  MaxDist := Dist;
+  for Index := 1 to High(FPolygon^) do
+  begin
+    Dist := Distance(Pt, FPolygon^[Index]);
+    if Dist < MinDist then
+      MinDist := Dist
+    else
+    if Dist > MaxDist then
+      MaxDist := Dist;
+  end;
+  Result := LutPtr^[WrapProc(Round((MaxDist + MinDist) * FScale),
+    LutMask)];
+end;
+
+procedure TMyGradient.SetRadius(const Value: TFloat);
+begin
+  if FRadius <> Value then
+  begin
+    FRadius := Value;
+    FInitialized := False;
+  end;
+end;
+
+procedure TMyGradient.UpdateInternals;
+begin
+  inherited;
+  FScale := LutMask / FRadius;
+end;
+
+procedure TMyGradient.AssignTo(Dest: TPersistent);
+begin
+  inherited;
+end;
+
+
+{ TFrmGradientSampler }
+
+procedure TFrmGradientSampler.FormCreate(Sender: TObject);
+var
+  Index: Integer;
+begin
+  FGradientSampler := TDiamondGradientSampler.Create;
+  FCenter := FloatPoint(0.5 * PaintBox32.Width, 0.5 * PaintBox32.Height);
+  FGradCenter := FCenter;
+  FAngle := 0.4;
+  FRadius := 50;
+  FWrapMode := wmMirror;
+  FStarVertices := 5;
+  FStarAngle := 0;
+  FOutline := Star(FCenter, 180, FStarVertices, FStarAngle);
+
+  FBackgroundGradientSampler := TBarycentricGradientSampler.Create;
+  SetLength(FMesh, FBackgroundGradientSampler.Count);
+  for Index := 0 to High(FMesh) do
+  begin
+    FMesh[Index].Point := FloatPoint(PaintBox32.Width * Random,
+      PaintBox32.Height * Random);
+    FMesh[Index].Velocity := FloatPoint(2 * Random - 1, 2 * Random - 1);
+    FMesh[Index].Color := SetAlpha(Random($FFFFFF), $FF);
+    FMesh[Index].HueChange := 0.001 * (2 * Random - 1);
+  end;
+  FStartColor := SetAlpha(Random($FFFFFF), $FF);
+  FEndColor := SetAlpha(Random($FFFFFF), $FF);
+
+  UpdateBackgroundGradientSampler;
+
+{$ifndef GR32_WRAPMODE_REFLECT}
+  MnuWrapModeReflect.Enabled := False;
+{$endif}
+
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.UpdateBackgroundGradientSampler;
+var
+  Index: Integer;
+begin
+  for Index := 0 to FBackgroundGradientSampler.Count - 1 do
+  begin
+    FBackgroundGradientSampler.Point[Index] := FMesh[Index].Point;
+    FBackgroundGradientSampler.Color[Index] := FMesh[Index].Color;
+  end;
+end;
+
+procedure TFrmGradientSampler.FormDestroy(Sender: TObject);
+begin
+  FBackgroundGradientSampler.Free;
+  FGradientSampler.Free;
+end;
+
+procedure TFrmGradientSampler.FormKeyDown(Sender: TObject; var Key: Word;
+  Shift: TShiftState);
+begin
+  case Key of
+    27: Close;
+    52..57:
+      begin
+        FStarVertices := Key - 48;
+        FOutline := Star(FCenter, 180, FStarVertices);
+        PaintBox32.Invalidate;
+      end;
+  end;
+end;
+
+procedure TFrmGradientSampler.MnuCloseClick(Sender: TObject);
+begin
+  Close;
+end;
+
+procedure TFrmGradientSampler.MnuGradientRadialClick(Sender: TObject);
+var
+  OldGradientSampler: TCustomGradientSampler;
+begin
+  OldGradientSampler := FGradientSampler;
+  FGradientSampler := TRadialGradientSampler.Create;
+  FGradientSampler.Assign(OldGradientSampler);
+  OldGradientSampler.Free;
+  MnuGradientRadial.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.MnuGradientConicClick(Sender: TObject);
+var
+  OldGradientSampler: TCustomGradientSampler;
+begin
+  OldGradientSampler := FGradientSampler;
+  FGradientSampler := TConicGradientSampler.Create;
+  FGradientSampler.Assign(OldGradientSampler);
+  OldGradientSampler.Free;
+  MnuGradientConic.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.MnuGradientCustomClick(Sender: TObject);
+var
+  OldGradientSampler: TCustomGradientSampler;
+begin
+  OldGradientSampler := FGradientSampler;
+  FGradientSampler := TMyGradient.Create;
+  FGradientSampler.Assign(OldGradientSampler);
+  OldGradientSampler.Free;
+  MnuGradientCustom.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.MnuGradientDiamondClick(Sender: TObject);
+var
+  OldGradientSampler: TCustomGradientSampler;
+begin
+  OldGradientSampler := FGradientSampler;
+  FGradientSampler := TDiamondGradientSampler.Create;
+  FGradientSampler.Assign(OldGradientSampler);
+  OldGradientSampler.Free;
+  MnuGradientDiamond.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.MnuGradientXYClick(Sender: TObject);
+var
+  OldGradientSampler: TCustomGradientSampler;
+begin
+  OldGradientSampler := FGradientSampler;
+  FGradientSampler := TXYGradientSampler.Create;
+  FGradientSampler.Assign(OldGradientSampler);
+  OldGradientSampler.Free;
+  MnuGradientXY.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.MnuGradientXYSqrtClick(Sender: TObject);
+var
+  OldGradientSampler: TCustomGradientSampler;
+begin
+  OldGradientSampler := FGradientSampler;
+  FGradientSampler := TXYSqrtGradientSampler.Create;
+  FGradientSampler.Assign(OldGradientSampler);
+  OldGradientSampler.Free;
+  MnuGradientXYSqrt.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.MnuBackgroundGradientCustomIDWClick(
+  Sender: TObject);
+var
+  Index: Integer;
+begin
+  if not MnuBackgroundGradientCustomIDW.Checked then
+  begin
+    MnuBackgroundGradientCustomIDW.Checked := True;
+    FBackgroundGradientSampler.Free;
+    FBackgroundGradientSampler := TInvertedDistanceWeightingSampler.Create;
+    TInvertedDistanceWeightingSampler(FBackgroundGradientSampler).Power := 8;
+    with TCustomArbitrarySparsePointGradientSampler(FBackgroundGradientSampler) do
+      for Index := 0 to High(FMesh) do
+        Add(FMesh[Index].Point, FMesh[Index].Color);
+    PaintBox32.Invalidate;
+  end;
+end;
+
+procedure TFrmGradientSampler.MnuBackgroundGradientShepardsClick(Sender: TObject);
+var
+  Index: Integer;
+begin
+  if not MnuBackgroundGradientShepards.Checked then
+  begin
+    MnuBackgroundGradientShepards.Checked := True;
+    FBackgroundGradientSampler.Free;
+    FBackgroundGradientSampler := TInvertedDistanceWeightingSampler.Create;
+    with TCustomArbitrarySparsePointGradientSampler(FBackgroundGradientSampler) do
+      for Index := 0 to High(FMesh) do
+        Add(FMesh[Index].Point, FMesh[Index].Color);
+    PaintBox32.Invalidate;
+  end;
+end;
+
+procedure TFrmGradientSampler.MnuBackgroundGradientTriangularClick(Sender: TObject);
+begin
+  if not MnuBackgroundGradientTriangular.Checked then
+  begin
+    MnuBackgroundGradientTriangular.Checked := True;
+    FBackgroundGradientSampler.Free;
+    FBackgroundGradientSampler := TBarycentricGradientSampler.Create;
+    UpdateBackgroundGradientSampler;
+    PaintBox32.Invalidate;
+  end;
+end;
+
+procedure TFrmGradientSampler.MnuBackgroundGradientVoronoiClick(Sender: TObject);
+var
+  Index: Integer;
+begin
+  if not MnuBackgroundGradientVoronoi.Checked then
+  begin
+    MnuBackgroundGradientVoronoi.Checked := True;
+    FBackgroundGradientSampler.Free;
+    FBackgroundGradientSampler := TVoronoiSampler.Create;
+    with TCustomArbitrarySparsePointGradientSampler(FBackgroundGradientSampler) do
+      for Index := 0 to High(FMesh) do
+        Add(FMesh[Index].Point, FMesh[Index].Color);
+    PaintBox32.Invalidate;
+  end;
+end;
+
+procedure TFrmGradientSampler.MnuWrapModeClampClick(Sender: TObject);
+begin
+  FWrapMode := wmClamp;
+  MnuWrapModeClamp.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.MnuWrapModeMirrorClick(Sender: TObject);
+begin
+  FWrapMode := wmMirror;
+  MnuWrapModeMirror.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.MnuWrapModeReflectClick(Sender: TObject);
+begin
+{$ifdef GR32_WRAPMODE_REFLECT}
+  FWrapMode := wmReflect;
+  MnuWrapModeReflect.Checked := True;
+  PaintBox32.Invalidate;
+{$endif}
+end;
+
+procedure TFrmGradientSampler.MnuWrapModeRepeatClick(Sender: TObject);
+begin
+  FWrapMode := wmRepeat;
+  MnuWrapModeRepeat.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.MnuGradientLinearClick(Sender: TObject);
+var
+  OldGradientSampler: TCustomGradientSampler;
+begin
+  OldGradientSampler := FGradientSampler;
+  FGradientSampler := TXGradientSampler.Create;
+  FGradientSampler.Assign(OldGradientSampler);
+  OldGradientSampler.Free;
+  MnuGradientLinear.Checked := True;
+  PaintBox32.Invalidate;
+end;
+
+procedure TFrmGradientSampler.PaintBox32DblClick(Sender: TObject);
+begin
+  Animation.Enabled := not Animation.Enabled;
+end;
+
+procedure TFrmGradientSampler.PaintBox32MouseDown(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+var
+  Index: Integer;
+begin
+  if (ssCtrl in Shift) then
+  begin
+    Animation.Enabled := not Animation.Enabled;
+    Exit;
+  end;
+
+  if (ssShift in Shift) then
+  begin
+    for Index := 0 to 2 do
+    begin
+      FMesh[Index].Point := FloatPoint(PaintBox32.Width * Random, PaintBox32.Height * Random);
+      FMesh[Index].Velocity := FloatPoint(2 * Random - 1, 2 * Random - 1);
+      FMesh[Index].Color := SetAlpha(Random($FFFFFF), $FF);
+      FMesh[Index].HueChange := 0.001 * (2 * Random - 1);
+    end;
+    UpdateBackgroundGradientSampler;
+
+    FStartColor := SetAlpha(Random($FFFFFF), $FF);
+    FEndColor := SetAlpha(Random($FFFFFF), $FF);
+
+    PaintBox32.Invalidate;
+    Exit;
+  end;
+
+  PaintBox32.OnMouseMove := PaintBox32MouseMove;
+  if ssRight in Shift then
+  begin
+    if ssShift in Shift then
+      FCenter := FloatPoint(X, Y)
+    else
+      FGradCenter := FloatPoint(X, Y);
+    PaintBox32.Invalidate;
+  end;
+  FLastPos := FloatPoint(X, Y);
+end;
+
+procedure TFrmGradientSampler.PaintBox32MouseMove(Sender: TObject;
+  Shift: TShiftState; X, Y: Integer);
+var
+  Dist: TFloat;
+begin
+  if (ssRight in Shift) then
+  begin
+    if (ssShift in Shift) then
+      FCenter := FloatPoint(X, Y)
+    else
+      FGradCenter := FloatPoint(X, Y);
+    PaintBox32.Invalidate;
+  end else
+  if (ssLeft in Shift) then
+  begin
+    if (Y <> FGradCenter.Y) or (X <> FGradCenter.X) then
+    begin
+      FAngle := FAngle - ArcTan2(Y - FGradCenter.Y, X - FGradCenter.X) +
+        ArcTan2(FLastPos.Y - FGradCenter.Y, FLastPos.X - FGradCenter.X);
+      Dist := Distance(FLastPos, FGradCenter);
+      if (Dist > 0) then
+        FRadius := FRadius * (Hypot(Y - FGradCenter.Y, X - FGradCenter.X) / Dist);
+
+      PaintBox32.Invalidate;
+    end;
+  end;
+  FLastPos := FloatPoint(X, Y);
+end;
+
+procedure TFrmGradientSampler.PaintBox32MouseUp(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+  PaintBox32.OnMouseMove := nil;
+end;
+
+procedure TFrmGradientSampler.PaintBox32PaintBuffer(Sender: TObject);
+var
+  Renderer: TPolygonRenderer32;
+  SamplerFiller: TSamplerFiller;
+  X, Y: Integer;
+begin
+  PaintBox32.Buffer.Clear(clWhite32);
+
+  FBackgroundGradientSampler.PrepareSampling;
+  with PaintBox32.Buffer do
+    for Y := 0 to Height - 1 do
+      for X := 0 to Width - 1 do
+        Pixel[X, Y] := FBackgroundGradientSampler.GetSampleInt(X, Y);
+
+  Renderer := TPolygonRenderer32VPR.Create(PaintBox32.Buffer);
+  try
+    Renderer.Color := clWhite32;
+
+    if FGradientSampler is TCustomCenterRadiusLutGradientSampler then
+      TCustomCenterRadiusLutGradientSampler(FGradientSampler).Radius := FRadius;
+
+    if FGradientSampler is TCustomCenterRadiusAngleLutGradientSampler then
+      with TCustomCenterRadiusAngleLutGradientSampler(FGradientSampler) do
+        Angle := FAngle;
+
+    if FGradientSampler is TConicGradientSampler then
+      TConicGradientSampler(FGradientSampler).Angle := FAngle;
+
+    if FGradientSampler is TCustomCenterLutGradientSampler then
+      TCustomCenterLutGradientSampler(FGradientSampler).Center := FGradCenter;
+
+    FGradientSampler.Gradient.StartColor := FStartColor;
+    FGradientSampler.Gradient.EndColor := FEndColor;
+    FGradientSampler.WrapMode := FWrapMode;
+
+    SamplerFiller := TSamplerFiller.Create(FGradientSampler);
+    try
+      Renderer.Filler := SamplerFiller;
+
+      if FGradientSampler is TMyGradient then
+        with TMyGradient(FGradientSampler) do
+        begin
+          Polygon := @FOutline;
+          Radius := Self.FRadius;
+        end;
+
+      Renderer.PolygonFS(FOutline);
+    finally
+      SamplerFiller.Free;
+    end;
+
+    Renderer.Filler := nil;
+    Renderer.Color := clBlack32;
+    Renderer.PolyPolygonFS(BuildPolyPolyline(PolyPolygon(FOutline), True, 5,
+      jsRound, esRound));
+  finally
+    Renderer.Free;
+  end;
+end;
+
+procedure TFrmGradientSampler.AnimationTimer(Sender: TObject);
+var
+  Index: Integer;
+  H, S, L: Single;
+begin
+  FAngle := FAngle + 0.01;
+  FStarAngle := FStarAngle + 0.01;
+  FOutline := Star(FCenter, 180, FStarVertices, FStarAngle);
+
+  for Index := 0 to FBackgroundGradientSampler.Count - 1 do
+  begin
+    FMesh[Index].Point.X := FMesh[Index].Point.X + FMesh[Index].Velocity.X;
+    if FMesh[Index].Point.X < 0 then
+    begin
+      FMesh[Index].Point.X := -FMesh[Index].Point.X;
+      FMesh[Index].Velocity.X := -FMesh[Index].Velocity.X;
+    end;
+
+    if FMesh[Index].Point.X >= PaintBox32.Width then
+    begin
+      FMesh[Index].Point.X := 2 * PaintBox32.Width - FMesh[Index].Point.X;
+      FMesh[Index].Velocity.X := -FMesh[Index].Velocity.X;
+    end;
+
+    FMesh[Index].Point.Y := FMesh[Index].Point.Y + FMesh[Index].Velocity.Y;
+    if FMesh[Index].Point.Y < 0 then
+    begin
+      FMesh[Index].Point.Y := -FMesh[Index].Point.Y;
+      FMesh[Index].Velocity.Y := -FMesh[Index].Velocity.Y;
+    end;
+
+    FMesh[Index].Point.Y := FMesh[Index].Point.Y + FMesh[Index].Velocity.Y;
+    if FMesh[Index].Point.Y >= PaintBox32.Height then
+    begin
+      FMesh[Index].Point.Y := 2 * PaintBox32.Height - FMesh[Index].Point.Y;
+      FMesh[Index].Velocity.Y := -FMesh[Index].Velocity.Y;
+    end;
+    RGBtoHSL(FMesh[Index].Color, H, S, L);
+    FMesh[Index].Color := HSLtoRGB(H + FMesh[Index].HueChange, S, L);
+  end;
+  UpdateBackgroundGradientSampler;
+
+  PaintBox32.Invalidate;
+end;
+
+end.

+ 1 - 0
Externals/Graphics32/Examples/Drawing/GradSampler/Media.rc

@@ -0,0 +1 @@
+MainIcon ICON "../../Media/GR32.ico"

+ 17 - 0
Externals/Graphics32/Examples/Drawing/Grow/Grow.dpr

@@ -0,0 +1,17 @@
+program Grow;
+
+
+
+
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas' {FormGrow};
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFormGrow, FormGrow);
+  Application.Run;
+end.

+ 149 - 0
Externals/Graphics32/Examples/Drawing/Grow/Grow.dproj

@@ -0,0 +1,149 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>Grow.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{df38204c-9381-46e3-b185-4a1c66830847}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">Grow</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>Grow</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas">
+            <Form>FormGrow</Form>
+        </DCCReference>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">Grow.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 277 - 0
Externals/Graphics32/Examples/Drawing/Grow/MainUnit.dfm

@@ -0,0 +1,277 @@
+object FormGrow: TFormGrow
+  Left = 224
+  Top = 159
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  Caption = 'Grow Example'
+  ClientHeight = 459
+  ClientWidth = 542
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = MainMenu
+  Position = poScreenCenter
+  TextHeight = 13
+  object Image: TImage32
+    AlignWithMargins = True
+    Left = 8
+    Top = 8
+    Width = 526
+    Height = 443
+    Margins.Left = 8
+    Margins.Top = 8
+    Margins.Right = 8
+    Margins.Bottom = 8
+    Align = alClient
+    Bitmap.ResamplerClassName = 'TNearestResampler'
+    BitmapAlign = baCustom
+    Scale = 1.000000000000000000
+    ScaleMode = smScale
+    MousePan.Enabled = True
+    MouseZoom.Enabled = True
+    TabOrder = 0
+    OnClick = ImageClick
+    OnResize = ImageResize
+  end
+  object MainMenu: TMainMenu
+    Left = 74
+    Top = 42
+    object MenuItemFile: TMenuItem
+      Caption = '&File'
+      object MenuItemRefresh: TMenuItem
+        Action = ActionRefresh
+      end
+      object N1: TMenuItem
+        Caption = '-'
+      end
+      object MenuItemExit: TMenuItem
+        Action = ActionFileExit
+      end
+    end
+    object MenuItemOptions: TMenuItem
+      Caption = '&Options'
+      object MenuItemOptionsInflatePolygon: TMenuItem
+        Action = ActionOptionShapePolygon
+        AutoCheck = True
+        GroupIndex = 1
+        RadioItem = True
+      end
+      object MenuItemOptionsInflatePolyLine: TMenuItem
+        Action = ActionOptionShapePolyLine
+        AutoCheck = True
+        GroupIndex = 1
+        RadioItem = True
+      end
+      object N2: TMenuItem
+        Caption = '-'
+        GroupIndex = 1
+      end
+      object Joinstyle1: TMenuItem
+        Action = ActionOptionJoinStyle
+        GroupIndex = 1
+        object Miterjoin1: TMenuItem
+          Action = ActionOptionJoinMiter
+          Checked = True
+          GroupIndex = 2
+          RadioItem = True
+        end
+        object Beveljoin1: TMenuItem
+          Action = ActionOptionJoinBevel
+          GroupIndex = 2
+          RadioItem = True
+        end
+        object Beveljoin2: TMenuItem
+          Action = ActionOptionJoinRound
+          GroupIndex = 2
+          RadioItem = True
+        end
+        object RoundExjoin2: TMenuItem
+          Action = ActionOptionJoinRoundEx
+          GroupIndex = 2
+        end
+        object RoundExjoin1: TMenuItem
+          Action = ActionOptionJoinSquare
+          GroupIndex = 2
+          RadioItem = True
+        end
+      end
+      object Endstyle1: TMenuItem
+        Action = ActionOptionEndStyle
+        GroupIndex = 1
+        object Action51: TMenuItem
+          Action = ActionOptionEndButt
+          Checked = True
+          GroupIndex = 3
+          RadioItem = True
+        end
+        object Action52: TMenuItem
+          Action = ActionOptionEndSquare
+          GroupIndex = 3
+          RadioItem = True
+        end
+        object Action71: TMenuItem
+          Action = ActionOptionEndRound
+          GroupIndex = 3
+          RadioItem = True
+        end
+      end
+      object N3: TMenuItem
+        Caption = '-'
+        GroupIndex = 1
+      end
+      object Growusing1: TMenuItem
+        Caption = 'Offset using...'
+        GroupIndex = 1
+        object Graphics321: TMenuItem
+          Action = ActionOptionGrowGraphics32
+          AutoCheck = True
+          GroupIndex = 4
+          RadioItem = True
+        end
+        object Image321: TMenuItem
+          Action = ActionOptionGrowAngus
+          AutoCheck = True
+          GroupIndex = 4
+        end
+        object Clipper1: TMenuItem
+          Action = ActionOptionGrowClipper
+          AutoCheck = True
+          GroupIndex = 4
+          RadioItem = True
+        end
+      end
+    end
+  end
+  object ActionList: TActionList
+    Left = 76
+    Top = 96
+    object ActionRefresh: TAction
+      Caption = '&Refresh'
+      ShortCut = 13
+      OnExecute = ActionRefreshExecute
+    end
+    object ActionFileExit: TAction
+      Caption = 'E&xit'
+      ShortCut = 27
+      OnExecute = ActionFileExitExecute
+    end
+    object ActionOptionShapePolygon: TAction
+      Category = 'Options'
+      AutoCheck = True
+      Caption = '&Polygon'
+      GroupIndex = 1
+      ShortCut = 16464
+      OnExecute = ActionOptionShapeExecute
+    end
+    object ActionOptionShapePolyLine: TAction
+      Category = 'Options'
+      AutoCheck = True
+      Caption = 'Poly&Line'
+      Checked = True
+      GroupIndex = 1
+      ShortCut = 16460
+      OnExecute = ActionOptionShapeExecute
+    end
+    object ActionOptionJoinStyle: TAction
+      Category = 'Options'
+      Caption = '&Join style'
+      OnExecute = ActionDummyExecute
+    end
+    object ActionOptionJoinMiter: TAction
+      Category = 'Options'
+      Caption = '&Miter join'
+      GroupIndex = 2
+      OnExecute = ActionOptionJoinStyleExecute
+      OnUpdate = ActionOptionJoinStyleUpdate
+    end
+    object ActionOptionJoinBevel: TAction
+      Tag = 1
+      Category = 'Options'
+      Caption = '&Bevel join'
+      GroupIndex = 2
+      OnExecute = ActionOptionJoinStyleExecute
+      OnUpdate = ActionOptionJoinStyleUpdate
+    end
+    object ActionOptionJoinRound: TAction
+      Tag = 2
+      Category = 'Options'
+      Caption = '&Round join'
+      GroupIndex = 2
+      OnExecute = ActionOptionJoinStyleExecute
+      OnUpdate = ActionOptionJoinStyleUpdate
+    end
+    object ActionOptionJoinRoundEx: TAction
+      Tag = 3
+      Category = 'Options'
+      Caption = 'RoundEx join'
+      GroupIndex = 2
+      OnExecute = ActionOptionJoinStyleExecute
+      OnUpdate = ActionOptionJoinStyleUpdate
+    end
+    object ActionOptionJoinSquare: TAction
+      Tag = 4
+      Category = 'Options'
+      Caption = '&Square join'
+      GroupIndex = 2
+      OnExecute = ActionOptionJoinStyleExecute
+      OnUpdate = ActionOptionJoinStyleUpdate
+    end
+    object ActionOptionEndStyle: TAction
+      Category = 'Options'
+      Caption = '&End style'
+      OnExecute = ActionDummyExecute
+      OnUpdate = ActionOptionEndStylesUpdate
+    end
+    object ActionOptionEndButt: TAction
+      Category = 'Options'
+      Caption = '&Butt end'
+      GroupIndex = 3
+      OnExecute = ActionOptionEndStyleExecute
+      OnUpdate = ActionOptionEndStyleUpdate
+    end
+    object ActionOptionEndSquare: TAction
+      Tag = 1
+      Category = 'Options'
+      Caption = '&Square end'
+      GroupIndex = 3
+      OnExecute = ActionOptionEndStyleExecute
+      OnUpdate = ActionOptionEndStyleUpdate
+    end
+    object ActionOptionEndRound: TAction
+      Tag = 2
+      Category = 'Options'
+      Caption = '&Round end'
+      GroupIndex = 3
+      OnExecute = ActionOptionEndStyleExecute
+      OnUpdate = ActionOptionEndStyleUpdate
+    end
+    object ActionOptionGrowGraphics32: TAction
+      Category = 'Options'
+      AutoCheck = True
+      Caption = 'Graphics32 reference'
+      Checked = True
+      GroupIndex = 4
+      ShortCut = 32817
+      OnExecute = ActionRedrawExecute
+    end
+    object ActionOptionGrowAngus: TAction
+      Category = 'Options'
+      AutoCheck = True
+      Caption = 'Image32'
+      GroupIndex = 4
+      ShortCut = 32818
+      OnExecute = ActionRedrawExecute
+    end
+    object ActionOptionGrowClipper: TAction
+      Category = 'Options'
+      AutoCheck = True
+      Caption = 'Clipper'
+      GroupIndex = 4
+      ShortCut = 32819
+      OnExecute = ActionRedrawExecute
+    end
+  end
+end

+ 348 - 0
Externals/Graphics32/Examples/Drawing/Grow/MainUnit.pas

@@ -0,0 +1,348 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is Clipper grow example
+ *
+ * The Initial Developer of the Original Code is
+ * Angus Johnson (http://www.angusj.com)
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFDEF FPC}LCLIntf, LResources, {$ENDIF}
+  Windows, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,
+  ExtCtrls, Math, Vcl.ExtDlgs, Vcl.Menus, System.Actions, Vcl.ActnList,
+
+  GR32,
+  GR32_Polygons,
+  GR32_VectorUtils,
+  GR32_Image;
+
+type
+  TFormGrow = class(TForm)
+    Image: TImage32;
+    MainMenu: TMainMenu;
+    MenuItemFile: TMenuItem;
+    N1: TMenuItem;
+    MenuItemExit: TMenuItem;
+    MenuItemRefresh: TMenuItem;
+    MenuItemOptions: TMenuItem;
+    MenuItemOptionsInflatePolygon: TMenuItem;
+    MenuItemOptionsInflatePolyLine: TMenuItem;
+    ActionList: TActionList;
+    ActionRefresh: TAction;
+    ActionFileExit: TAction;
+    ActionOptionShapePolygon: TAction;
+    ActionOptionShapePolyLine: TAction;
+    Joinstyle1: TMenuItem;
+    N2: TMenuItem;
+    Endstyle1: TMenuItem;
+    Miterjoin1: TMenuItem;
+    Beveljoin1: TMenuItem;
+    Beveljoin2: TMenuItem;
+    RoundExjoin1: TMenuItem;
+    ActionOptionJoinMiter: TAction;
+    ActionOptionJoinBevel: TAction;
+    ActionOptionJoinRound: TAction;
+    ActionOptionJoinSquare: TAction;
+    ActionOptionEndButt: TAction;
+    ActionOptionEndSquare: TAction;
+    ActionOptionEndRound: TAction;
+    Action51: TMenuItem;
+    Action52: TMenuItem;
+    Action71: TMenuItem;
+    ActionOptionJoinStyle: TAction;
+    ActionOptionEndStyle: TAction;
+    ActionOptionGrowClipper: TAction;
+    ActionOptionGrowGraphics32: TAction;
+    N3: TMenuItem;
+    Growusing1: TMenuItem;
+    Graphics321: TMenuItem;
+    Clipper1: TMenuItem;
+    ActionOptionGrowAngus: TAction;
+    Image321: TMenuItem;
+    ActionOptionJoinRoundEx: TAction;
+    RoundExjoin2: TMenuItem;
+    procedure ImageClick(Sender: TObject);
+    procedure ImageResize(Sender: TObject);
+    procedure ActionFileExitExecute(Sender: TObject);
+    procedure ActionOptionShapeExecute(Sender: TObject);
+    procedure ActionOptionJoinStyleExecute(Sender: TObject);
+    procedure ActionOptionEndStyleExecute(Sender: TObject);
+    procedure ActionDummyExecute(Sender: TObject);
+    procedure ActionOptionEndStylesUpdate(Sender: TObject);
+    procedure ActionOptionJoinStyleUpdate(Sender: TObject);
+    procedure ActionOptionEndStyleUpdate(Sender: TObject);
+    procedure ActionRefreshExecute(Sender: TObject);
+    procedure ActionRedrawExecute(Sender: TObject);
+  private
+    FJoinStyle: TJoinStyle;
+    FEndStyle: TEndStyle;
+    FPolyPoints: TArrayOfArrayOfFloatPoint;
+    function GeneratePolygon(MaxWidth, MaxHeight, EdgeCount: integer): TArrayOfFloatPoint;
+    procedure ApplyOptionsAndRedraw;
+    procedure CreateNewPolygonAndApplyOptions;
+    function PolyLineBuilderClass: TPolyLineBuilderClass;
+  public
+  end;
+
+var
+  FormGrow: TFormGrow;
+
+implementation
+
+{$IFDEF FPC}
+{$R *.lfm}
+{$ELSE}
+{$R *.dfm}
+{$ENDIF}
+
+uses
+  GR32_Clipper,
+  GR32_Paths,
+  GR32_VectorUtils.Reference,
+  GR32_VectorUtils.Angus,
+  GR32_VectorUtils.Clipper2;
+
+const
+  MARGIN = 40;
+
+//------------------------------------------------------------------------------
+
+function Area(const Path: TArrayOfFloatPoint): Single;
+var
+  i, j, HighI: Integer;
+  d: Single;
+begin
+  Result := 0.0;
+  HighI := High(Path);
+  if (HighI < 2) then Exit;
+  j := HighI;
+  for i := 0 to HighI do
+  begin
+    d := (Path[j].X + Path[i].X);
+    Result := Result + d * (Path[j].Y - Path[i].Y);
+    j := i;
+  end;
+  Result := -Result * 0.5;
+end;
+
+//------------------------------------------------------------------------------
+
+function MakeRandomPath(MaxWidth, MaxHeight, Count: Integer): TArrayOfFloatPoint;
+var
+  i: Integer;
+begin
+  Setlength(Result, Count);
+  for i := 0 to Count -1 do
+  begin
+    Result[i].X := MARGIN + Random(MaxWidth - MARGIN * 2);
+    Result[i].Y := MARGIN + Random(MaxHeight - MARGIN * 2);
+  end;
+end;
+
+//------------------------------------------------------------------------------
+
+function TFormGrow.GeneratePolygon(MaxWidth, MaxHeight, EdgeCount: integer): TArrayOfFloatPoint;
+
+  function Union(const Paths: TArrayOfArrayOfFloatPoint; FillRule: TFillRule = frEvenOdd): TArrayOfArrayOfFloatPoint;
+  var
+    Clipper: TClipper;
+  begin
+    Clipper := TClipper.Create;
+    try
+      Clipper.AddPaths(Paths, ptSubject, False);
+      Clipper.Execute(ctUnion, FillRule, Result);
+    finally
+      Clipper.Free;
+    end;
+  end;
+
+var
+  PolyPts: TArrayOfArrayOfFloatPoint;
+  i,j: integer;
+  Area, a: Single;
+begin
+  Setlength(PolyPts, 1);
+  PolyPts[0] := MakeRandomPath(MaxWidth, MaxHeight, EdgeCount);
+
+  // NOTE: INFLATEPATHS WILL BEHAVE IN AN UNDETERMINED FASHION
+  // WHENEVER SELF-INTERSECTING POLYGONS ARE ENCOUNTERED.
+
+  // so, remove self-intersections
+  PolyPts := Union(PolyPts);
+
+  if (Length(PolyPts) = 0) then
+    // Most likely user has resized window to zero size
+    Abort;
+
+  // and find the largest polygon ...
+  j := 0;
+  Area := Abs(MainUnit.Area(PolyPts[0]));
+  for i := 1 to high(PolyPts) do
+  begin
+    a := Abs(MainUnit.Area(PolyPts[i]));
+    if a <= Area then
+      Continue;
+    j := i;
+    Area := a;
+  end;
+
+  Result := PolyPts[j];
+end;
+
+//------------------------------------------------------------------------------
+
+function TFormGrow.PolyLineBuilderClass: TPolyLineBuilderClass;
+begin
+  if (ActionOptionGrowClipper.Checked) then
+    Result := PolyLineBuilderClipper
+  else
+  if (ActionOptionGrowAngus.Checked) then
+    Result := PolyLineBuilderAngus
+  else
+    Result := PolyLineBuilderReference;
+end;
+
+//------------------------------------------------------------------------------
+
+procedure TFormGrow.ActionOptionEndStylesUpdate(Sender: TObject);
+begin
+  TAction(Sender).Enabled := not ActionOptionShapePolygon.Checked;
+end;
+
+procedure TFormGrow.ActionDummyExecute(Sender: TObject);
+begin
+//
+end;
+
+procedure TFormGrow.ActionFileExitExecute(Sender: TObject);
+begin
+  Close;
+end;
+
+procedure TFormGrow.ActionOptionEndStyleUpdate(Sender: TObject);
+begin
+  TAction(Sender).Enabled := (TEndStyle(TAction(Sender).Tag) in PolyLineBuilderClass.SupportedEndStyles);
+  TAction(Sender).Checked := (FEndStyle = TEndStyle(TAction(Sender).Tag));
+end;
+
+procedure TFormGrow.ActionOptionEndStyleExecute(Sender: TObject);
+begin
+  FEndStyle := TEndStyle(TAction(Sender).Tag);
+  ApplyOptionsAndRedraw;
+end;
+
+procedure TFormGrow.ActionOptionShapeExecute(Sender: TObject);
+begin
+  CreateNewPolygonAndApplyOptions;
+end;
+
+procedure TFormGrow.ActionOptionJoinStyleUpdate(Sender: TObject);
+begin
+  TAction(Sender).Enabled := (TJoinStyle(TAction(Sender).Tag) in PolyLineBuilderClass.SupportedJoinStyles);
+  TAction(Sender).Checked := (FJoinStyle = TJoinStyle(TAction(Sender).Tag));
+end;
+
+procedure TFormGrow.ActionRedrawExecute(Sender: TObject);
+begin
+  ApplyOptionsAndRedraw;
+end;
+
+procedure TFormGrow.ActionRefreshExecute(Sender: TObject);
+begin
+  CreateNewPolygonAndApplyOptions;
+end;
+
+procedure TFormGrow.ActionOptionJoinStyleExecute(Sender: TObject);
+begin
+  FJoinStyle := TJoinStyle(TAction(Sender).Tag);
+  ApplyOptionsAndRedraw;
+end;
+
+procedure TFormGrow.ApplyOptionsAndRedraw;
+var
+  PolyPts: TArrayOfArrayOfFloatPoint;
+  Closed: boolean;
+  Builder: TPolyLineBuilderClass;
+begin
+  // Apply options to existing polyline/polygon and repaint
+
+  Closed := not ActionOptionShapePolyLine.Checked;
+
+  Image.Bitmap.Clear(clWhite32);
+
+  if (Closed) then
+    PolyPolygonFS(image.Bitmap, FPolyPoints, $100000FF, pfNonZero);
+  PolyPolylineFS(image.Bitmap, FPolyPoints, clBlack32, Closed, 1);
+
+  Builder := PolyLineBuilderClass;
+
+  PolyPts := Builder.BuildPolyPolyLine(FPolyPoints, Closed, 20, FJoinStyle, FEndStyle);
+
+  PolyPolylineFS(image.Bitmap, PolyPts, clRed32, True, 1);
+  PolyPolygonFS(image.Bitmap, PolyPts, $10FF0000, pfNonZero);
+end;
+
+procedure TFormGrow.ImageResize(Sender: TObject);
+begin
+  Image.Bitmap.SetSize(Image.ClientWidth, Image.ClientHeight);
+  CreateNewPolygonAndApplyOptions;
+end;
+
+procedure TFormGrow.CreateNewPolygonAndApplyOptions;
+begin
+  if (Image.Bitmap.Width < 2*MARGIN) or (Image.Bitmap.Height < 2*MARGIN) then
+  begin
+    Image.Bitmap.Clear(clRed32);
+    exit;
+  end;
+
+  Caption := IntToStr(RandSeed);
+
+  Setlength(FPolyPoints, 1);
+
+  if ActionOptionShapePolyLine.Checked then
+    // Generate a polyline
+    FPolyPoints[0] := MakeRandomPath(Image.Bitmap.Width, Image.Bitmap.Height, 7)
+  else
+    // Generate a closed polygon
+    repeat
+      FPolyPoints[0] := GeneratePolygon(Image.Bitmap.Width, Image.Bitmap.Height, 5);
+    until Length(FPolyPoints[0]) > 3;
+
+  ApplyOptionsAndRedraw;
+end;
+
+procedure TFormGrow.ImageClick(Sender: TObject);
+begin
+  CreateNewPolygonAndApplyOptions;
+end;
+
+end.

+ 2 - 0
Externals/Graphics32/Examples/Drawing/Grow/Media.rc

@@ -0,0 +1,2 @@
+MainIcon ICON "../../Media/GR32.ico"
+

+ 744 - 0
Externals/Graphics32/Examples/Drawing/LineStippling/LineStippling.cbproj

@@ -0,0 +1,744 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{35844EF1-92E1-454C-823C-6FDB54020649}</ProjectGuid>
+        <ProjectVersion>18.6</ProjectVersion>
+        <FrameworkType>VCL</FrameworkType>
+        <AppType>Application</AppType>
+        <MainSource>LineStippling.cpp</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>3</TargetedPlatforms>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+        <DynamicRTL>true</DynamicRTL>
+        <UsePackages>true</UsePackages>
+        <IntermediateOutputDir>lib</IntermediateOutputDir>
+        <FinalOutputDir>bin</FinalOutputDir>
+        <BCC_wpar>false</BCC_wpar>
+        <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
+        <BCC_ExtendedErrorInfo>true</BCC_ExtendedErrorInfo>
+        <ILINK_TranslatedLibraryPath>$(BDSLIB)\$(PLATFORM)\release\$(LANGDIR);$(ILINK_TranslatedLibraryPath)</ILINK_TranslatedLibraryPath>
+        <ProjectType>CppVCLApplication</ProjectType>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
+        <AllPackageLibs>rtl.lib;vcl.lib;GR32_R.lib</AllPackageLibs>
+        <_TCHARMapping>wchar_t</_TCHARMapping>
+        <Multithreaded>true</Multithreaded>
+        <Icon_MainIcon>$(BDS)\bin\cbuilder_PROJECTICON.ico</Icon_MainIcon>
+        <UWP_CppLogo44>$(BDS)\bin\Artwork\Windows\UWP\cppreg_UwpDefault_44.png</UWP_CppLogo44>
+        <UWP_CppLogo150>$(BDS)\bin\Artwork\Windows\UWP\cppreg_UwpDefault_150.png</UWP_CppLogo150>
+        <IncludePath>$(IncludePath)</IncludePath>
+        <ILINK_LibraryPath>$(ILINK_LibraryPath)</ILINK_LibraryPath>
+        <SanitizedProjectName>LineStippling</SanitizedProjectName>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <DCC_HppOutputARM>true</DCC_HppOutputARM>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <PackageImports>adortl;appanalytics;bcbie;bcbsmp;bindcomp;bindcompdbx;bindcompfmx;bindcompvcl;bindengine;CloudService;CustomIPTransport;DataSnapClient;DataSnapCommon;DataSnapConnectors;DatasnapConnectorsFreePascal;DataSnapFireDAC;DataSnapIndy10ServerTransport;DataSnapNativeClient;DataSnapProviderClient;DataSnapServer;DataSnapServerMidas;dbexpress;dbrtl;dbxcds;DbxClientDriver;DbxCommonDriver;DBXDb2Driver;DBXFirebirdDriver;DBXInformixDriver;DBXInterBaseDriver;DBXMSSQLDriver;DBXMySQLDriver;DBXOdbcDriver;DBXOracleDriver;DBXSqliteDriver;DBXSybaseASADriver;DBXSybaseASEDriver;dsnap;dsnapcon;dsnapxml;emsclient;emsclientfiredac;emsedge;emshosting;emsserverresource;FireDAC;FireDACADSDriver;FireDACASADriver;FireDACCommon;FireDACCommonDriver;FireDACCommonODBC;FireDACDb2Driver;FireDACDBXDriver;FireDACDSDriver;FireDACIBDriver;FireDACInfxDriver;FireDACMongoDBDriver;FireDACMSAccDriver;FireDACMSSQLDriver;FireDACMySQLDriver;FireDACODBCDriver;FireDACOracleDriver;FireDACPgDriver;FireDACSqliteDriver;FireDACTDataDriver;fmx;fmxase;fmxdae;fmxFireDAC;fmxobj;FMXTee;FmxTeeUI;GR32_D;GR32_R;IndyCore;IndyIPClient;IndyIPCommon;IndyIPServer;IndyProtocols;IndySystem;inet;inetdb;inetdbxpress;RESTBackendComponents;RESTComponents;rtl;soapmidas;soaprtl;soapserver;svn;SynEdit_BCB;Tee;TeeDB;TeeUI;tethering;vcl;vclactnband;vcldb;vcldsnap;vclFireDAC;vclie;vclimg;VCLRESTComponents;VclSmp;vcltouch;vclwinx;vclx;xmlrtl;$(PackageImports)</PackageImports>
+        <IncludePath>$(BDSINCLUDE)\windows\vcl;$(IncludePath)</IncludePath>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <PackageImports>adortl;appanalytics;bcbie;bcbsmp;bindcomp;bindcompdbx;bindcompfmx;bindcompvcl;bindengine;CloudService;CustomIPTransport;DataSnapClient;DataSnapCommon;DataSnapConnectors;DatasnapConnectorsFreePascal;DataSnapFireDAC;DataSnapIndy10ServerTransport;DataSnapNativeClient;DataSnapProviderClient;DataSnapServer;DataSnapServerMidas;dbexpress;dbrtl;dbxcds;DbxClientDriver;DbxCommonDriver;DBXDb2Driver;DBXFirebirdDriver;DBXInformixDriver;DBXInterBaseDriver;DBXMSSQLDriver;DBXMySQLDriver;DBXOdbcDriver;DBXOracleDriver;DBXSqliteDriver;DBXSybaseASADriver;DBXSybaseASEDriver;dsnap;dsnapcon;dsnapxml;emsclient;emsclientfiredac;emsedge;emshosting;emsserverresource;FireDAC;FireDACADSDriver;FireDACASADriver;FireDACCommon;FireDACCommonDriver;FireDACCommonODBC;FireDACDb2Driver;FireDACDBXDriver;FireDACDSDriver;FireDACIBDriver;FireDACInfxDriver;FireDACMongoDBDriver;FireDACMSAccDriver;FireDACMSSQLDriver;FireDACMySQLDriver;FireDACODBCDriver;FireDACOracleDriver;FireDACPgDriver;FireDACSqliteDriver;FireDACTDataDriver;fmx;fmxase;fmxdae;fmxFireDAC;fmxobj;FMXTee;FmxTeeUI;GR32_R;IndyCore;IndyIPClient;IndyIPCommon;IndyIPServer;IndyProtocols;IndySystem;inet;inetdb;inetdbxpress;RESTBackendComponents;RESTComponents;rtl;soapmidas;soaprtl;soapserver;Tee;TeeDB;TeeUI;tethering;vcl;vclactnband;vcldb;vcldsnap;vclFireDAC;vclie;vclimg;VCLRESTComponents;VclSmp;vcltouch;vclwinx;vclx;xmlrtl;$(PackageImports)</PackageImports>
+        <IncludePath>$(BDSINCLUDE)\windows\vcl;$(IncludePath)</IncludePath>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
+        <BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <Defines>_DEBUG;$(Defines)</Defines>
+        <BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
+        <BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
+        <DCC_Define>DEBUG</DCC_Define>
+        <BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
+        <TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
+        <BCC_StackFrames>true</BCC_StackFrames>
+        <ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
+        <TASM_Debugging>Full</TASM_Debugging>
+        <BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
+        <BCC_EnableCPPExceptions>true</BCC_EnableCPPExceptions>
+        <BCC_DisableFramePtrElimOpt>true</BCC_DisableFramePtrElimOpt>
+        <BCC_DisableSpellChecking>true</BCC_DisableSpellChecking>
+        <CLANG_UnwindTables>true</CLANG_UnwindTables>
+        <ILINK_LibraryPath>$(BDSLIB)\$(PLATFORM)\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+        <ILINK_TranslatedLibraryPath>$(BDSLIB)\$(PLATFORM)\debug\$(LANGDIR);$(ILINK_TranslatedLibraryPath)</ILINK_TranslatedLibraryPath>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+        <BCC_UseClassicCompiler>false</BCC_UseClassicCompiler>
+        <LinkPackageImports>rtl.bpi;vcl.bpi;GR32_R.bpi</LinkPackageImports>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+        <LinkPackageImports>rtl.bpi;vcl.bpi;GR32_R.bpi</LinkPackageImports>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <Defines>NDEBUG;$(Defines)</Defines>
+        <TASM_Debugging>None</TASM_Debugging>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+        <BCC_UseClassicCompiler>false</BCC_UseClassicCompiler>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
+    </PropertyGroup>
+    <ItemGroup>
+        <CppCompile Include="LineStippling.cpp">
+            <BuildOrder>0</BuildOrder>
+        </CppCompile>
+        <DelphiCompile Include="MainUnit.pas">
+            <BuildOrder>2</BuildOrder>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>CPlusPlusBuilder.Personality.12</Borland.Personality>
+        <Borland.ProjectType>CppVCLApplication</Borland.ProjectType>
+        <BorlandProject>
+            <CPlusPlusBuilder.Personality>
+                <ProjectProperties>
+                    <ProjectProperties Name="AutoShowDeps">False</ProjectProperties>
+                    <ProjectProperties Name="ManagePaths">True</ProjectProperties>
+                    <ProjectProperties Name="VerifyPackages">True</ProjectProperties>
+                    <ProjectProperties Name="IndexFiles">False</ProjectProperties>
+                </ProjectProperties>
+                <Source>
+                    <Source Name="MainSource">LineStippling.cpp</Source>
+                </Source>
+                <Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcboffice2k260.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcbofficexp260.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
+                </Excluded_Packages>
+            </CPlusPlusBuilder.Personality>
+            <Deployment Version="3">
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\bin\cc32c260.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx32\libcgcrtl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx64\libcgstl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\bin\cc32260mt.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\bin\cc32260.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx32\libcgstl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(UsingDelphiRTL)'=='true'" LocalName="$(BDS)\bin\borlndmm.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(UsingDelphiRTL)'=='true'" LocalName="$(BDS)\bin64\borlndmm.dll" Class="DependencyModule">
+                    <Platform Name="Win64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\bin64\cc64260mt.dll" Class="DependencyModule">
+                    <Platform Name="Win64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="..\..\..\Binaries\Win32\Debug\LineStippling.tds" Configuration="Debug" Class="DebugSymbols">
+                    <Platform Name="Win32">
+                        <RemoteName>LineStippling.tds</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="..\..\..\Binaries\Win32\Debug\LineStippling.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>LineStippling.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\bin64\cc64260.dll" Class="DependencyModule">
+                    <Platform Name="Win64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\bin\cc32c260mt.dll" Class="DependencyModule">
+                    <Platform Name="Win32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\Redist\osx64\libcgcrtl.dylib" Class="DependencyModule">
+                    <Platform Name="OSX64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1536">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2048">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch768">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_CppLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_CppLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Cpp.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Cpp.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

+ 34 - 0
Externals/Graphics32/Examples/Drawing/LineStippling/LineStippling.cpp

@@ -0,0 +1,34 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("LineStippling.res");
+USEFORMNS("MainUnit.pas", Mainunit, FormLineStippling);
+//---------------------------------------------------------------------------
+int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
+{
+	try
+	{
+		Application->Initialize();
+		Application->MainFormOnTaskBar = true;
+		Application->CreateForm(__classid(TFormLineStippling), &FormLineStippling);
+		Application->Run();
+	}
+	catch (Exception &exception)
+	{
+		Application->ShowException(&exception);
+	}
+	catch (...)
+	{
+		try
+		{
+			throw Exception("");
+		}
+		catch (Exception &exception)
+		{
+			Application->ShowException(&exception);
+		}
+	}
+	return 0;
+}
+//---------------------------------------------------------------------------

+ 15 - 0
Externals/Graphics32/Examples/Drawing/LineStippling/LineStippling.dpr

@@ -0,0 +1,15 @@
+program LineStippling;
+
+{$R 'Media.res' 'Media.rc'}
+
+uses
+  Forms,
+  MainUnit in 'MainUnit.pas';
+
+{$R '..\manifest.res'}
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TFormLineStippling, FormLineStippling);
+  Application.Run;
+end.

+ 167 - 0
Externals/Graphics32/Examples/Drawing/LineStippling/LineStippling.dproj

@@ -0,0 +1,167 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <Base>True</Base>
+        <AppType>Application</AppType>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <FrameworkType>VCL</FrameworkType>
+        <MainSource>LineStippling.dpr</MainSource>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <ProjectGuid>{53c68669-2800-4c4c-bf9d-b5c0d8e6ad13}</ProjectGuid>
+        <ProjectVersion>20.3</ProjectVersion>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <ProjectName Condition="'$(ProjectName)'==''">LineStippling</ProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
+        <Cfg_1_Win64>true</Cfg_1_Win64>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
+        <Cfg_2_Win32>true</Cfg_2_Win32>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
+        <Cfg_2_Win64>true</Cfg_2_Win64>
+        <CfgParent>Cfg_2</CfgParent>
+        <Cfg_2>true</Cfg_2>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <SanitizedProjectName>LineStippling</SanitizedProjectName>
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <DCC_DcuOutput>.\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_ImageBase>00400000</DCC_ImageBase>
+        <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMX;Winapi;$(DCC_Namespace)</DCC_Namespace>
+        <DCC_UnitSearchPath>..\..\..\Source;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Keys>CompanyName=Graphics32;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+        <BT_BuildType>Debug</BT_BuildType>
+        <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_Optimize>false</DCC_Optimize>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
+        <BRCC_CompilerToUse>rc</BRCC_CompilerToUse>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
+        <AppEnableHighDPI>true</AppEnableHighDPI>
+        <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <RcCompile Include="Media.rc">
+            <Form>Media.res</Form>
+        </RcCompile>
+        <DCCReference Include="MainUnit.pas"/>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType/>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">LineStippling.dpr</Source>
+                </Source>
+                <Excluded_Packages/>
+                <VersionInfo>
+                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+                    <VersionInfo Name="MajorVer">1</VersionInfo>
+                    <VersionInfo Name="MinorVer">0</VersionInfo>
+                    <VersionInfo Name="Release">0</VersionInfo>
+                    <VersionInfo Name="Build">0</VersionInfo>
+                    <VersionInfo Name="Debug">False</VersionInfo>
+                    <VersionInfo Name="PreRelease">False</VersionInfo>
+                    <VersionInfo Name="Special">False</VersionInfo>
+                    <VersionInfo Name="Private">False</VersionInfo>
+                    <VersionInfo Name="DLL">False</VersionInfo>
+                    <VersionInfo Name="Locale">1033</VersionInfo>
+                    <VersionInfo Name="CodePage">1252</VersionInfo>
+                </VersionInfo>
+                <VersionInfoKeys>
+                    <VersionInfoKeys Name="CompanyName"/>
+                    <VersionInfoKeys Name="FileDescription"/>
+                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="InternalName"/>
+                    <VersionInfoKeys Name="LegalCopyright"/>
+                    <VersionInfoKeys Name="LegalTrademarks"/>
+                    <VersionInfoKeys Name="OriginalFilename"/>
+                    <VersionInfoKeys Name="ProductName"/>
+                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+                    <VersionInfoKeys Name="Comments"/>
+                </VersionInfoKeys>
+            </Delphi.Personality>
+            <Platforms>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+</Project>

+ 51 - 0
Externals/Graphics32/Examples/Drawing/LineStippling/MainUnit.dfm

@@ -0,0 +1,51 @@
+object FormLineStippling: TFormLineStippling
+  Left = 216
+  Top = 109
+  Caption = 'Line Stippling Example'
+  ClientHeight = 221
+  ClientWidth = 249
+  Color = clBtnFace
+  Constraints.MinHeight = 260
+  Constraints.MinWidth = 265
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  ShowHint = True
+  DesignSize = (
+    249
+    221)
+  TextHeight = 13
+  object PaintBox: TPaintBox32
+    Left = 8
+    Top = 10
+    Width = 200
+    Height = 200
+    Hint = 'Click to animate'
+    Anchors = [akLeft, akTop, akRight, akBottom]
+    TabOrder = 0
+    OnClick = PaintBoxClick
+    OnPaintBuffer = PaintBoxPaintBuffer
+  end
+  object ScrollBar: TScrollBar
+    Left = 224
+    Top = 10
+    Width = 16
+    Height = 200
+    Anchors = [akTop, akRight, akBottom]
+    Kind = sbVertical
+    Min = 1
+    PageSize = 0
+    Position = 50
+    TabOrder = 1
+    OnChange = ScrollBarChange
+  end
+  object TimerAnimate: TTimer
+    Enabled = False
+    Interval = 50
+    OnTimer = TimerAnimateTimer
+    Left = 104
+    Top = 92
+  end
+end

+ 150 - 0
Externals/Graphics32/Examples/Drawing/LineStippling/MainUnit.pas

@@ -0,0 +1,150 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1 or LGPL 2.1 with linking exception
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Free Pascal modified version of the GNU Lesser General Public License
+ * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
+ * of this license are applicable instead of those above.
+ * Please see the file LICENSE.txt for additional information concerning this
+ * license.
+ *
+ * The Original Code is Line Stippling Example
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$include GR32.inc}
+
+uses
+  {$IFDEF FPC} LCLIntf, LResources, {$ENDIF}
+  SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
+  GR32,
+  GR32_Image;
+
+type
+  TFormLineStippling = class(TForm)
+    PaintBox: TPaintBox32;
+    ScrollBar: TScrollBar;
+    TimerAnimate: TTimer;
+    procedure ScrollBarChange(Sender: TObject);
+    procedure PaintBoxPaintBuffer(Sender: TObject);
+    procedure PaintBoxClick(Sender: TObject);
+    procedure TimerAnimateTimer(Sender: TObject);
+  private
+    FStippleCounter: Single;
+  public
+    procedure Spiral(X, Y: Integer);
+  end;
+
+var
+  FormLineStippling: TFormLineStippling;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Math,
+  GR32_Gamma,
+  GR32_Math;
+
+{ TFormLineStippling }
+
+procedure TFormLineStippling.PaintBoxClick(Sender: TObject);
+begin
+  TimerAnimate.Enabled := not TimerAnimate.Enabled;
+end;
+
+procedure TFormLineStippling.PaintBoxPaintBuffer(Sender: TObject);
+var
+  Step: Single;
+  Stipple: TArrayOfColor32;
+begin
+  Step := ScrollBar.Position * 0.01;
+
+  PaintBox.Buffer.BeginUpdate;
+  try
+
+    PaintBox.Buffer.Clear(clBlack32);
+    PaintBox.Buffer.StippleStep := Step;
+
+    // Note that we are not using PaintBox.Buffer.Width & Height since
+    // PaintBox.BufferOversize might cause the buffer to be bigger than
+    // the control.
+
+    // Dynamic array of colors
+    Stipple := [clWhite32, clWhite32, clWhite32, clWhite32, 0, 0, 0, 0];
+    PaintBox.Buffer.SetStipple(Stipple);
+    PaintBox.Buffer.StippleCounter := FStippleCounter;
+    Spiral(PaintBox.Width div 4, PaintBox.Height div 4);
+
+    // Static array of colors
+    PaintBox.Buffer.SetStipple([clWhite32, $00FFFFFF]);
+    PaintBox.Buffer.StippleCounter := FStippleCounter;
+    Spiral(3*PaintBox.Width div 4, PaintBox.Height div 4);
+
+    PaintBox.Buffer.SetStipple([clWhite32, clRed32, clGreen32, 0, 0, 0]);
+    PaintBox.Buffer.StippleCounter := FStippleCounter;
+    Spiral(PaintBox.Width div 4, 3*PaintBox.Height div 4);
+
+    PaintBox.Buffer.SetStipple([clGreen32, clGreen32, clGreen32, 0, 0, clWhite32, 0, 0]);
+    PaintBox.Buffer.StippleCounter := FStippleCounter;
+    Spiral(3*PaintBox.Width div 4, 3*PaintBox.Height div 4);
+
+  finally
+    PaintBox.Buffer.EndUpdate;
+  end;
+end;
+
+procedure TFormLineStippling.ScrollBarChange(Sender: TObject);
+begin
+  PaintBox.Invalidate;
+end;
+
+procedure TFormLineStippling.Spiral(X, Y: Integer);
+var
+  Theta: Single;
+  Sn, Cn: Single;
+  Step: Single;
+begin
+  PaintBox.Buffer.MoveToF(X, Y);
+
+  Theta := 0;
+  Step := 40 / Max(PaintBox.Width, PaintBox.Height);
+
+  while Theta < 15 * Pi do
+  begin
+    GR32_Math.SinCos(Theta, Sn, Cn);
+    PaintBox.Buffer.LineToFSP(X + Cn * Theta * (PaintBox.Width / 220), Y + Sn * Theta * (PaintBox.Height / 220));
+    Theta := Theta + Step;
+  end;
+end;
+
+procedure TFormLineStippling.TimerAnimateTimer(Sender: TObject);
+begin
+  FStippleCounter := FStippleCounter + 0.1;
+  PaintBox.Invalidate;
+end;
+
+end.

+ 1 - 0
Externals/Graphics32/Examples/Drawing/LineStippling/Media.rc

@@ -0,0 +1 @@
+MainIcon ICON "../../Media/GR32.ico"

+ 53 - 0
Externals/Graphics32/Examples/Drawing/LineStippling/createbundle.sh

@@ -0,0 +1,53 @@
+#!/bin/sh
+# Force Bourne shell in case tcsh is default.
+#
+appname=LineStippling
+appfolder=$appname.app
+macosfolder=$appfolder/Contents/MacOS
+plistfile=$appfolder/Contents/Info.plist
+appfile=$appname
+#
+if ! [ -e $appfile ]
+then
+  echo "$appfile does not exist"
+elif [ -e $appfolder ]
+then
+  echo "$appfolder already exists"
+else
+  echo "Creating $appfolder..."
+  mkdir $appfolder
+  mkdir $appfolder/Contents
+  mkdir $appfolder/Contents/MacOS
+  mkdir $appfolder/Contents/Resources
+#
+# Instead of copying executable into .app folder after each compile,
+# simply create a symbolic link to executable.
+  ln -s ../../../$appname $macosfolder/$appname
+# Also create a symbolic link for the resource files
+  ln -s ../../../../../../Media $appfolder/Contents/Resources/Media
+#
+# Create PkgInfo file.
+  echo "APPL????" >$appfolder/Contents/PkgInfo
+#
+# Create information property list file (Info.plist).
+  echo '<?xml version="1.0" encoding="UTF-8"?>' >$plistfile
+  echo '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >>$plistfile
+  echo '<plist version="1.0">' >>$plistfile
+  echo '<dict>' >>$plistfile
+  echo '  <key>CFBundleDevelopmentRegion</key>' >>$plistfile
+  echo '  <string>English</string>' >>$plistfile
+  echo '  <key>CFBundleExecutable</key>' >>$plistfile
+  echo '  <string>'$appname'</string>' >>$plistfile
+  echo '  <key>CFBundleInfoDictionaryVersion</key>' >>$plistfile
+  echo '  <string>6.0</string>' >>$plistfile
+  echo '  <key>CFBundlePackageType</key>' >>$plistfile
+  echo '  <string>APPL</string>' >>$plistfile
+  echo '  <key>CFBundleSignature</key>' >>$plistfile
+  echo '  <string>????</string>' >>$plistfile
+  echo '  <key>CFBundleVersion</key>' >>$plistfile
+  echo '  <string>1.0</string>' >>$plistfile
+  echo '  <key>CSResourcesFileMapped</key>' >>$plistfile
+  echo '  <true/>' >>$plistfile
+  echo '</dict>' >>$plistfile
+  echo '</plist>' >>$plistfile
+fi

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels