Browse Source

Merge branch pas2js:main into updateJsPDF

reyn claros 3 months ago
parent
commit
2bd638c7b9

File diff suppressed because it is too large
+ 0 - 0
demo/wasienv/memutils/bulma.min.css


+ 52 - 0
demo/wasienv/memutils/index.html

@@ -0,0 +1,52 @@
+
+<!doctype html>
+<html lang="en">
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <title>FPC-Webassembly and Pas2JS Demo</title>
+  <link href="bulma.min.css" rel="stylesheet">
+  <!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css"> -->
+  <script src="memtesthost.js"></script>
+  <style>
+
+  .source {
+    /* width: 730px; */
+    margin: -45px auto;
+    font-size: 0.9em;
+  }
+
+  .source-inner {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    /* width: 482px; */
+  }
+  </style>
+</head>
+<body>
+  <div class="section pb-4">
+    <h1 class="title is-4">Wasm & Host program console output:</h1>
+    Both the webassembly program and the host program in JS track the
+    growing of webassembly linear memory. They both log a line when the
+    memory array is resized.
+    <div class="box" id="pasjsconsole"></div>
+  </div>
+  <!-- <hr> -->
+  <div class="section">
+    <div class="source">
+      <div class="source-inner">
+        <div>
+          <p>Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> </p>
+          <p>Pas2JS Sources: &nbsp; <a target="new" href="memtesthost.lpr">Pas2JS Program</a></p>
+          <p>Webassembly Sources: &nbsp; <a target="new" href="testmem.pp">FPC Program</a></p>
+        </div>
+      </div>
+    </div>
+  </div>
+  <script>
+    rtl.showUncaughtExceptions=true;
+    rtl.run();
+  </script>
+</body>
+</html>

+ 92 - 0
demo/wasienv/memutils/memtesthost.lpi

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+        <Runnable Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="memtesthost"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="2">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="PasJSWebBrowserProject" Value="1"/>
+    </CustomData>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="memtesthost.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="index.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit>
+      <Unit>
+        <Filename Value="../../../packages/wasm-utils/src/wasm.pas2js.memutils.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="memtesthost"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <UseAnsiStrings Value="False"/>
+        <CPPInline Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 126 - 0
demo/wasienv/memutils/memtesthost.lpr

@@ -0,0 +1,126 @@
+program memtesthost;
+
+{$mode objfpc}
+
+uses
+  browserconsole, browserapp, JS, Classes, SysUtils, Web, WebAssembly, types, wasienv, wasm.pas2js.memutils;
+
+Type
+
+  { TMyApplication }
+
+  TMyApplication = class(TBrowserApplication)
+  Private
+    FWasiEnv: TPas2JSWASIEnvironment;
+    FMemUtils : TWasiMemUtils;
+    FMemory : TJSWebAssemblyMemory; // Memory of webassembly
+    FTable : TJSWebAssemblyTable; // exported functions.
+    function CreateWebAssembly(Path: string; ImportObject: TJSObject
+      ): TJSPromise;
+    procedure DoWrite(Sender: TObject; const aOutput: String);
+    procedure HandleMemoryGrow(aPages: Integer);
+    function initEnv(aValue: JSValue): JSValue;
+    procedure InitWebAssembly;
+  Public
+    Constructor Create(aOwner : TComponent); override;
+    Destructor Destroy; override;
+    procedure doRun; override;
+  end;
+
+function TMyApplication.InitEnv(aValue: JSValue): JSValue;
+
+Var
+  Module : TJSInstantiateResult absolute aValue;
+  exps : TWASIExports;
+
+begin
+  Result:=True;
+  Exps := TWASIExports(TJSObject(Module.Instance.exports_));
+  FWasiEnv.Instance:=Module.Instance;
+  Exps.Start;
+end;
+
+procedure TMyApplication.DoWrite(Sender: TObject; const aOutput: String);
+begin
+  Writeln(aOutput);
+end;
+
+procedure TMyApplication.HandleMemoryGrow(aPages: Integer);
+begin
+  Writeln('Webassembly host: memory has grown with ',aPages,' pages of 64k');
+end;
+
+constructor TMyApplication.Create(aOwner: TComponent);
+begin
+  inherited Create(aOwner);
+  FWasiEnv:=TPas2JSWASIEnvironment.Create;
+  FWasiEnv.OnStdErrorWrite:=@DoWrite;
+  FWasiEnv.OnStdOutputWrite:=@DoWrite;
+  FMemUtils:=TWasiMemUtils.Create(FWasiEnv);
+  FMemUtils.OnMemoryGrow:=@HandleMemoryGrow;
+end;
+
+function TMyApplication.CreateWebAssembly(Path: string; ImportObject: TJSObject): TJSPromise;
+
+begin
+  Result:=window.fetch(Path)._then(Function (res : jsValue) : JSValue
+    begin
+      Result:=TJSResponse(Res).arrayBuffer._then(Function (res2 : jsValue) : JSValue
+        begin
+          Result:=TJSWebAssembly.instantiate(TJSArrayBuffer(res2),ImportObject);
+        end,Nil)
+    end,Nil
+  );
+ end;
+
+procedure TMyApplication.InitWebAssembly;
+
+Var
+  mDesc : TJSWebAssemblyMemoryDescriptor;
+  tDesc: TJSWebAssemblyTableDescriptor;
+  ImportObj : TJSObject;
+
+begin
+  //  Setup memory
+  mDesc.initial:=256;
+  mDesc.maximum:=256;
+  FMemory:=TJSWebAssemblyMemory.New(mDesc);
+  // Setup table
+  tDesc.initial:=0;
+  tDesc.maximum:=0;
+  tDesc.element:='anyfunc';
+  FTable:=TJSWebAssemblyTable.New(tDesc);
+  // Setup ImportObject
+  ImportObj:=new([
+    'js', new([
+      'mem', FMemory,
+      'tbl', FTable
+    ])
+  ]);
+  FWasiEnv.AddImports(ImportObj);
+  CreateWebAssembly('memtest.wasm',ImportObj)._then(@initEnv)
+end;
+
+
+destructor TMyApplication.Destroy;
+begin
+  FreeAndNil(FWasiEnv);
+  inherited Destroy;
+end;
+
+procedure TMyApplication.doRun;
+
+begin
+  // Your code here
+  Terminate;
+  InitWebAssembly;
+end;
+
+var
+  Application : TMyApplication;
+
+begin
+  Application:=TMyApplication.Create(nil);
+  Application.Initialize;
+  Application.Run;
+end.

+ 60 - 0
demo/wasienv/memutils/testmem.lpi

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="testmem"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="testmem.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="wasm.memutils.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target>
+      <Filename Value="testmem.wasm"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 20 - 0
demo/wasienv/memutils/testmem.lpr

@@ -0,0 +1,20 @@
+program testmem;
+
+uses wasmtypes, webassembly, wasm.http.api, wasm.memutils;
+
+procedure DoGrow(aPages : longint);
+
+begin
+  writeln('Growing wasm memory with ',aPages,' pages of 64k');
+end;
+
+var
+  i : integer;
+  p : pointer;
+
+begin
+  MemGrowNotifyCallBack:=@DoGrow;
+  for I:=1 to 20 do
+    getmem(p,1024*256*i);
+end.
+

+ 18 - 2
packages/job/src/job_browser.pp

@@ -955,11 +955,27 @@ var
   var
     Len, Ptr: TWasmNativeInt;
     aWords: TJSUint16Array;
+    aRawBytes,
+    aBytes: TJSUint8Array;
   begin
     Len:=ReadWasmNativeInt;
     Ptr:=ReadWasmNativeInt;
-    aWords:=TJSUint16Array.New(View.buffer, Ptr,Len);
-    Result:=DecodeUTF16Buffer(aWords);
+    if (Ptr mod 2)=0 then
+      begin
+      // Aligned, we can directly use the memory
+      aWords:=TJSUint16Array.New(View.buffer, Ptr,Len);
+      end
+    else
+      begin
+      // Unaligned, We cannot directly use the memory
+      // So create a uint8 buffer and copy using from.
+     aRawBytes:=TJSUint8Array.new(View.buffer, Ptr,Len*2);
+      // Hopefully aligned
+      aBytes:=TJSUint8Array.New(aRawBytes.Buffer);
+      // Reinterpret
+      aWords:=TJSUint16Array.New(aBytes.buffer);
+      end;
+     Result:=DecodeUTF16Buffer(aWords);
     {$IFDEF VERBOSEJOB}
     Writeln('ReadUnicodeString : ',Result);
     {$ENDIF}

+ 5 - 15
packages/rtl/src/rtti.pas

@@ -243,7 +243,7 @@ type
     procedure LoadFlags;
     procedure LoadParameters;
   public
-    constructor Create(const Signature: TProcedureSignature);
+    constructor Create(const Parent: TRttiObject; const Signature: TProcedureSignature);
 
     class function Invoke(const Instance: TValue; const Args: array of TValue): TValue;
 
@@ -273,8 +273,6 @@ type
     function GetProcedureSignature: TRttiProcedureSignature;
     function GetReturnType: TRttiType;
   protected
-    function GetName: String; override;
-
     property ProcedureSignature: TRttiProcedureSignature read GetProcedureSignature;
   public
     function GetParameters: TRttiParameterArray;
@@ -2216,18 +2214,10 @@ begin
   Result := ProcedureSignature.ReturnType;
 end;
 
-function TRttiMethod.GetName: String;
-begin
-  Result := inherited;
-
-  if IsConstructor then
-    Result := Result.SubString(0, Result.IndexOf('$'));
-end;
-
 function TRttiMethod.GetProcedureSignature: TRttiProcedureSignature;
 begin
   if not Assigned(FProcedureSignature) then
-    FProcedureSignature := TRttiProcedureSignature.Create(MethodTypeInfo.ProcSig);
+    FProcedureSignature := TRttiProcedureSignature.Create(Self, MethodTypeInfo.ProcSig);
 
   Result := FProcedureSignature;
 end;
@@ -2872,9 +2862,9 @@ end;
 
 { TRttiProcedureSignature }
 
-constructor TRttiProcedureSignature.Create(const Signature: TProcedureSignature);
+constructor TRttiProcedureSignature.Create(const Parent: TRttiObject; const Signature: TProcedureSignature);
 begin
-  inherited Create(nil, Signature);
+  inherited Create(Parent, Signature);
 
   FReturnType := Pool.GetType(Signature.ResultType);
 
@@ -2927,7 +2917,7 @@ begin
   for A := Low(FParameters) to High(FParameters) do
   begin
     Param := MethodParams[A];
-    RttiParam := TRttiParameter.Create(Self, Param);
+    RttiParam := TRttiParameter.Create(Parent, Param);
     RttiParam.FName := Param.Name;
     RttiParam.FParamType := Pool.GetType(Param.TypeInfo);
 

+ 8 - 0
packages/rtl/src/system.pas

@@ -102,6 +102,7 @@ type
 {*****************************************************************************
             TObject, TClass, IUnknown, IInterface, TInterfacedObject
 *****************************************************************************}
+
 type
   TGuid = record
     D1: DWord;
@@ -121,6 +122,13 @@ type
   TClass = class of TObject;
 
   { TObject }
+  {$IFDEF ENABLE_DELPHI_RTTI}
+    {$RTTI INHERIT
+        METHODS([vcPublic, vcPublished])
+        FIELDS([vcPrivate,vcProtected, vcPublic,vcPublished])
+        PROPERTIES([vcPublic, vcPublished])
+    }
+  {$ENDIF}
 
   {$DispatchField Msg} // enable checking message methods for record field name "Msg"
   {$DispatchStrField MsgStr}

+ 1145 - 0
packages/rtl/src/system.uitypes.pp

@@ -0,0 +1,1145 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 1999-2019 by Marco van de Voort
+        member of the Free Pascal development team.
+
+    Delphi compatibility unit with GUI/imaging related types.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+unit System.UITypes;
+
+{$mode delphi}
+
+// LCL defined all sets with SizeOf()=4
+{$PACKSET FIXED}
+
+interface
+
+Type  
+    RTLString   = String;
+    TColor      = NativeInt; // -$7FFFFFFF-1..$7FFFFFFF; not handled correctly by pas2js
+    TColorRef   = Type Cardinal;
+    TAlphaColor = Type Cardinal;
+    TImageIndex = type Integer;
+
+    { TColorRec }
+
+    TColorRec = record
+      class var ColorToRGB: function (Color: TColor): Longint;
+      function GetColor : TColor;
+      procedure SetColor(aColor : TColor);
+      function ToString : RTLString;
+      const
+      // 140 HTML colors.
+      AliceBlue          = TColor($FFF8F0);
+      AntiqueWhite       = TColor($D7EBFA);
+      Aqua               = TColor($FFFF00);
+      Aquamarine         = TColor($D4FF7F);
+      Azure              = TColor($FFFFF0);
+      Beige              = TColor($DCF5F5);
+      Bisque             = TColor($C4E4FF);
+      Black              = TColor($000000);
+      BlanchedAlmond     = TColor($CDEBFF);
+      Blue               = TColor($FF0000);
+      BlueViolet         = TColor($E22B8A);
+      Brown              = TColor($2A2AA5);
+      BurlyWood          = TColor($87B8DE);
+      CadetBlue          = TColor($A09E5F);
+      Chartreuse         = TColor($00FF7F);
+      Chocolate          = TColor($1E69D2);
+      Coral              = TColor($507FFF);
+      CornflowerBlue     = TColor($ED9564);
+      Cornsilk           = TColor($DCF8FF);
+      Crimson            = TColor($3C14DC);
+      Cyan               = TColor($FFFF00);
+      DarkBlue           = TColor($8B0000);
+      DarkCyan           = TColor($8B8B00);
+      DarkGoldenRod      = TColor($0B86B8);
+      DarkGray           = TColor($A9A9A9);
+      DarkGreen          = TColor($006400);
+      DarkGrey           = TColor($A9A9A9);
+      DarkKhaki          = TColor($6BB7BD);
+      DarkMagenta        = TColor($8B008B);
+      DarkOliveGreen     = TColor($2F6B55);
+      DarkOrange         = TColor($008CFF);
+      DarkOrchid         = TColor($CC3299);
+      DarkRed            = TColor($00008B);
+      DarkSalmon         = TColor($7A96E9);
+      DarkSeaGreen       = TColor($8FBC8F);
+      DarkSlateBlue      = TColor($8B3D48);
+      DarkSlateGray      = TColor($4F4F2F);
+      DarkSlateGrey      = TColor($4F4F2F);
+      DarkTurquoise      = TColor($D1CE00);
+      DarkViolet         = TColor($D30094);
+      DeepPink           = TColor($9314FF);
+      DeepSkyBlue        = TColor($FFBF00);
+      DimGray            = TColor($696969);
+      DimGrey            = TColor($696969);
+      DodgerBlue         = TColor($FF901E);
+      FireBrick          = TColor($2222B2);
+      FloralWhite        = TColor($F0FAFF);
+      ForestGreen        = TColor($228B22);
+      Fuchsia            = TColor($FF00FF);
+      Gainsboro          = TColor($DCDCDC);
+      GhostWhite         = TColor($FFF8F8);
+      Gold               = TColor($00D7FF);
+      GoldenRod          = TColor($20A5DA);
+      Gray               = TColor($808080);
+      Green              = TColor($008000);
+      GreenYellow        = TColor($2FFFAD);
+      Grey               = TColor($808080);
+      HoneyDew           = TColor($F0FFF0);
+      HotPink            = TColor($B469FF);
+      IndianRed          = TColor($5C5CCD);
+      Indigo             = TColor($82004B);
+      Ivory              = TColor($F0FFFF);
+      Khaki              = TColor($8CE6F0);
+      Lavender           = TColor($FAE6E6);
+      LavenderBlush      = TColor($F5F0FF);
+      LawnGreen          = TColor($00FC7C);
+      LemonChiffon       = TColor($CDFAFF);
+      LightBlue          = TColor($E6D8AD);
+      LightCoral         = TColor($8080F0);
+      LightCyan          = TColor($FFFFE0);
+      LightGoldenRodYellow    = TColor($D2FAFA);
+      LightGray          = TColor($D3D3D3);
+      LightGreen         = TColor($90EE90);
+      LightGrey          = TColor($D3D3D3);
+      LightPink          = TColor($C1B6FF);
+      LightSalmon        = TColor($7AA0FF);
+      LightSeaGreen      = TColor($AAB220);
+      LightSkyBlue       = TColor($FACE87);
+      LightSlateGray     = TColor($998877);
+      LightSlateGrey     = TColor($998877);
+      LightSteelBlue     = TColor($DEC4B0);
+      LightYellow        = TColor($E0FFFF);
+      Lime               = TColor($00FF00);
+      LimeGreen          = TColor($32CD32);
+      Linen              = TColor($E6F0FA);
+      Magenta            = TColor($FF00FF);
+      Maroon             = TColor($000080);
+      MediumAquaMarine   = TColor($AACD66);
+      MediumBlue         = TColor($CD0000);
+      MediumOrchid       = TColor($D355BA);
+      MediumPurple       = TColor($DB7093);
+      MediumSeaGreen     = TColor($71B33C);
+      MediumSlateBlue    = TColor($EE687B);
+      MediumSpringGreen  = TColor($9AFA00);
+      MediumTurquoise    = TColor($CCD148);
+      MediumVioletRed    = TColor($8515C7);
+      MidnightBlue       = TColor($701919);
+      MintCream          = TColor($FAFFF5);
+      MistyRose          = TColor($E1E4FF);
+      Moccasin           = TColor($B5E4FF);
+      NavajoWhite        = TColor($ADDEFF);
+      Navy               = TColor($800000);
+      OldLace            = TColor($E6F5FD);
+      Olive              = TColor($008080);
+      OliveDrab          = TColor($238E6B);
+      Orange             = TColor($00A5FF);
+      OrangeRed          = TColor($0045FF);
+      Orchid             = TColor($D670DA);
+      PaleGoldenRod      = TColor($AAE8EE);
+      PaleGreen          = TColor($98FB98);
+      PaleTurquoise      = TColor($EEEEAF);
+      PaleVioletRed      = TColor($9370DB);
+      PapayaWhip         = TColor($D5EFFF);
+      PeachPuff          = TColor($B9DAFF);
+      Peru               = TColor($3F85CD);
+      Pink               = TColor($CBC0FF);
+      Plum               = TColor($DDA0DD);
+      PowderBlue         = TColor($E6E0B0);
+      Purple             = TColor($800080);
+      RebeccaPurple      = TColor($993366);
+      Red                = TColor($0000FF);
+      RosyBrown          = TColor($8F8FBC);
+      RoyalBlue          = TColor($E16941);
+      SaddleBrown        = TColor($13458B);
+      Salmon             = TColor($7280FA);
+      SandyBrown         = TColor($60A4F4);
+      SeaGreen           = TColor($578B2E);
+      SeaShell           = TColor($EEF5FF);
+      Sienna             = TColor($2D52A0);
+      Silver             = TColor($C0C0C0);
+      SkyBlue            = TColor($EBCE87);
+      SlateBlue          = TColor($CD5A6A);
+      SlateGray          = TColor($908070);
+      SlateGrey          = TColor($908070);
+      Snow               = TColor($FAFAFF);
+      SpringGreen        = TColor($7FFF00);
+      SteelBlue          = TColor($B48246);
+      Tan                = TColor($8CB4D2);
+      Teal               = TColor($808000);
+      Thistle            = TColor($D8BFD8);
+      Tomato             = TColor($4763FF);
+      Turquoise          = TColor($D0E040);
+      Violet             = TColor($EE82EE);
+      Wheat              = TColor($B3DEF5);
+      White              = TColor($FFFFFF);
+      WhiteSmoke         = TColor($F5F5F5);
+      Yellow             = TColor($00FFFF);
+      YellowGreen        = TColor($32CD9A);
+      // extended colors (from lazarus Graphics)
+      MoneyGreen         = TColor($C0DCC0);
+      Cream              = TColor($F0FBFF);
+      MedGray            = TColor($A4A0A0);
+      // aliases
+      LtGray             = TColor($C0C0C0); // clSilver alias
+      DkGray             = TColor($808080); // clGray alias
+      // Windows system colors
+      SysScrollBar               = TColor($FF000000) platform;
+      SysBackground              = TColor($FF000001) platform;
+      SysActiveCaption           = TColor($FF000002) platform;
+      SysInactiveCaption         = TColor($FF000003) platform;
+      SysMenu                    = TColor($FF000004) platform;
+      SysWindow                  = TColor($FF000005) platform;
+      SysWindowFrame             = TColor($FF000006) platform;
+      SysMenuText                = TColor($FF000007) platform;
+      SysWindowText              = TColor($FF000008) platform;
+      SysCaptionText             = TColor($FF000009) platform;
+      SysActiveBorder            = TColor($FF00000A) platform;
+      SysInactiveBorder          = TColor($FF00000B) platform;
+      SysAppWorkSpace            = TColor($FF00000C) platform;
+      SysHighlight               = TColor($FF00000D) platform;
+      SysHighlightText           = TColor($FF00000E) platform;
+      SysBtnFace                 = TColor($FF00000F) platform;
+      SysBtnShadow               = TColor($FF000010) platform;
+      SysGrayText                = TColor($FF000011) platform;
+      SysBtnText                 = TColor($FF000012) platform;
+      SysInactiveCaptionText     = TColor($FF000013) platform;
+      SysBtnHighlight            = TColor($FF000014) platform;
+      Sys3DDkShadow              = TColor($FF000015) platform;
+      Sys3DLight                 = TColor($FF000016) platform;
+      SysInfoText                = TColor($FF000017) platform;
+      SysInfoBk                  = TColor($FF000018) platform;
+      SysHotLight                = TColor($FF00001A) platform;
+      SysGradientActiveCaption   = TColor($FF00001B) platform;
+      SysGradientInactiveCaption = TColor($FF00001C) platform;
+      SysMenuHighlight           = TColor($FF00001D) platform;
+      SysMenuBar                 = TColor($FF00001E) platform;
+      SysNone                    = TColor($1FFFFFFF) platform;
+      Null                       = TColor($00000000);
+      SysDefault                 = TColor($20000000) platform;
+      var
+          R,G,B,A : Byte;
+          property Color : TColor read GetColor Write SetColor;
+      end;
+
+      TColors = TColorRec;
+
+
+  { TAlphaColors }
+
+  TAlphaColors = record
+    const
+      Null                 = TAlphaColor(0);
+      Alpha                = TAlphaColor($ff000000);
+      Black                = Alpha;
+      Blue                 = TAlphaColor($ff0000ff);
+      Green                = TAlphaColor($ff008000);
+      Lime                 = TAlphaColor($ff00ff00);
+      Red                  = TAlphaColor($ffff0000);
+      White                = TAlphaColor($ffffffff);
+      AliceBlue            = TAlphaColor($ffF0F8FF);
+      AntiqueWhite         = TAlphaColor($ffFAEBD7);
+      Aqua                 = TAlphaColor($ff00FFFF);
+      AquaMarine           = TAlphaColor($ff7FFFD4);
+      Azure                = TAlphaColor($ffF0FFFF);
+      Beige                = TAlphaColor($ffF5F5DC);
+      Bisque               = TAlphaColor($ffFFE4C4);
+      BlanchedAlmond       = TAlphaColor($ffFFEBCD);
+      BlueViolet           = TAlphaColor($ff8A2BE2);
+      Brown                = TAlphaColor($ffA52A2A);
+      BurlyWood            = TAlphaColor($ffDEB887);
+      CadetBlue            = TAlphaColor($ff5F9EA0);
+      Chartreuse           = TAlphaColor($ff7FFF00);
+      Chocolate            = TAlphaColor($ffD2691E);
+      Coral                = TAlphaColor($ffFF7F50);
+      CornflowerBlue       = TAlphaColor($ff6495ED);
+      CornSilk             = TAlphaColor($ffFFF8DC);
+      Crimson              = TAlphaColor($ffDC143C);
+      Cyan                 = TAlphaColor($ff00FFFF);
+      DarkBlue             = TAlphaColor($ff00008B);
+      DarkCyan             = TAlphaColor($ff008B8B);
+      DarkGoldenRod        = TAlphaColor($ffB8860B);
+      DarkGray             = TAlphaColor($ffA9A9A9);
+      DarkGreen            = TAlphaColor($ff006400);
+      DarkGrey             = TAlphaColor($ffA9A9A9);
+      DarkKhaki            = TAlphaColor($ffBDB76B);
+      DarkMagenta          = TAlphaColor($ff8B008B);
+      DarkOliveGreen       = TAlphaColor($ff556B2F);
+      DarkOrange           = TAlphaColor($ffFF8C00);
+      DarkOrchid           = TAlphaColor($ff9932CC);
+      DarkRed              = TAlphaColor($ff8B0000);
+      DarkSalmon           = TAlphaColor($ffE9967A);
+      DarkSeaGreen         = TAlphaColor($ff8FBC8F);
+      DarkSlateBlue        = TAlphaColor($ff483D8B);
+      DarkSlateGray        = TAlphaColor($ff2F4F4F);
+      DarkSlateGrey        = TAlphaColor($ff2F4F4F);
+      DarkTurquoise        = TAlphaColor($ff00CED1);
+      DarkViolet           = TAlphaColor($ff9400D3);
+      DeepPink             = TAlphaColor($ffFF1493);
+      DeepSkyBlue          = TAlphaColor($ff00BFFF);
+      DimGray              = TAlphaColor($ff696969);
+      DimGrey              = TAlphaColor($ff696969);
+      DodgerBlue           = TAlphaColor($ff1E90FF);
+      Firebrick            = TAlphaColor($ffB22222);
+      FloralWhite          = TAlphaColor($ffFFFAF0);
+      ForestGreen          = TAlphaColor($ff228B22);
+      Fuchsia              = TAlphaColor($ffFF00FF);
+      Gainsboro            = TAlphaColor($ffDCDCDC);
+      GhostWhite           = TAlphaColor($ffF8F8FF);
+      Gold                 = TAlphaColor($ffFFD700);
+      GoldenRod            = TAlphaColor($ffDAA520);
+      Gray                 = TAlphaColor($ff808080);
+      GreenYellow          = TAlphaColor($ffADFF2F);
+      Grey                 = TAlphaColor($ff808080);
+      HoneyDew             = TAlphaColor($ffF0FFF0);
+      HotPink              = TAlphaColor($ffFF69B4);
+      IndianRed            = TAlphaColor($ffCD5C5C);
+      Indigo               = TAlphaColor($ff4B0082);
+      Ivory                = TAlphaColor($ffFFFFF0);
+      Khaki                = TAlphaColor($ffF0E68C);
+      Lavender             = TAlphaColor($ffE6E6FA);
+      LavenderBlush        = TAlphaColor($ffFFF0F5);
+      LawnGreen            = TAlphaColor($ff7CFC00);
+      LemonChiffon         = TAlphaColor($ffFFFACD);
+      LightBlue            = TAlphaColor($ffADD8E6);
+      LightCoral           = TAlphaColor($ffF08080);
+      LightCyan            = TAlphaColor($ffE0FFFF);
+      LightGoldenRodYellow = TAlphaColor($ffFAFAD2);
+      LightGray            = TAlphaColor($ffD3D3D3);
+      LightGreen           = TAlphaColor($ff90EE90);
+      LightGrey            = TAlphaColor($ffD3D3D3);
+      LightPink            = TAlphaColor($ffFFB6C1);
+      LightSalmon          = TAlphaColor($ffFFA07A);
+      LightSeaGreen        = TAlphaColor($ff20B2AA);
+      LightSkyBlue         = TAlphaColor($ff87CEFA);
+      LightSlateGray       = TAlphaColor($ff778899);
+      LightSlateGrey       = TAlphaColor($ff778899);
+      LightSteelBlue       = TAlphaColor($ffB0C4DE);
+      LightYellow          = TAlphaColor($ffFFFFE0);
+      LtGray               = TAlphaColor($ffC0C0C0);
+      MedGray              = TAlphaColor($ffA0A0A0);
+      DkGray               = TAlphaColor($ff808080);
+      MoneyGreen           = TAlphaColor($ffC0DCC0);
+      LegacySkyBlue        = TAlphaColor($ffF0CAA6);
+      Cream                = TAlphaColor($ffF0FBFF);
+      LimeGreen            = TAlphaColor($ff32CD32);
+      Linen                = TAlphaColor($ffFAF0E6);
+      Magenta              = TAlphaColor($ffFF00FF);
+      Maroon               = TAlphaColor($ff800000);
+      MediumAquaMarine     = TAlphaColor($ff66CDAA);
+      MediumBlue           = TAlphaColor($ff0000CD);
+      MediumOrchid         = TAlphaColor($ffBA55D3);
+      MediumPurple         = TAlphaColor($ff9370DB);
+      MediumSeaGreen       = TAlphaColor($ff3CB371);
+      MediumSlateBlue      = TAlphaColor($ff7B68EE);
+      MediumSpringGreen    = TAlphaColor($ff00FA9A);
+      MediumTurquoise      = TAlphaColor($ff48D1CC);
+      MediumVioletRed      = TAlphaColor($ffC71585);
+      MidnightBlue         = TAlphaColor($ff191970);
+      MintCream            = TAlphaColor($ffF5FFFA);
+      MistyRose            = TAlphaColor($ffFFE4E1);
+      Moccasin             = TAlphaColor($ffFFE4B5);
+      NavajoWhite          = TAlphaColor($ffFFDEAD);
+      Navy                 = TAlphaColor($ff000080);
+      OldLace              = TAlphaColor($ffFDF5E6);
+      Olive                = TAlphaColor($ff808000);
+      OliveDrab            = TAlphaColor($ff6B8E23);
+      Orange               = TAlphaColor($ffFFA500);
+      OrangeRed            = TAlphaColor($ffFF4500);
+      Orchid               = TAlphaColor($ffDA70D6);
+      PaleGoldenRod        = TAlphaColor($ffEEE8AA);
+      PaleGreen            = TAlphaColor($ff98FB98);
+      PaleTurquoise        = TAlphaColor($ffAFEEEE);
+      PaleVioletRed        = TAlphaColor($ffDB7093);
+      PapayaWhip           = TAlphaColor($ffFFEFD5);
+      PeachPuff            = TAlphaColor($ffFFDAB9);
+      Peru                 = TAlphaColor($ffCD853F);
+      Pink                 = TAlphaColor($ffFFC0CB);
+      Plum                 = TAlphaColor($ffDDA0DD);
+      PowderBlue           = TAlphaColor($ffB0E0E6);
+      Purple               = TAlphaColor($ff800080);
+      RosyBrown            = TAlphaColor($ffBC8F8F);
+      RoyalBlue            = TAlphaColor($ff4169E1);
+      SaddleBrown          = TAlphaColor($ff8B4513);
+      Salmon               = TAlphaColor($ffFA8072);
+      SandyBrown           = TAlphaColor($ffF4A460);
+      SeaGreen             = TAlphaColor($ff2E8B57);
+      SeaShell             = TAlphaColor($ffFFF5EE);
+      Sienna               = TAlphaColor($ffA0522D);
+      Silver               = TAlphaColor($ffC0C0C0);
+      SkyBlue              = TAlphaColor($ff87CEEB);
+      SlateBlue            = TAlphaColor($ff6A5ACD);
+      SlateGray            = TAlphaColor($ff708090);
+      SlateGrey            = TAlphaColor($ff708090);
+      Snow                 = TAlphaColor($ffFFFAFA);
+      SpringGreen          = TAlphaColor($ff00FF7F);
+      SteelBlue            = TAlphaColor($ff4682B4);
+      Tan                  = TAlphaColor($ffD2B48C);
+      Teal                 = TAlphaColor($ff008080);
+      Thistle              = TAlphaColor($ffD8BFD8);
+      Tomato               = TAlphaColor($ffFF6347);
+      Turquoise            = TAlphaColor($ff40E0D0);
+      Violet               = TAlphaColor($ffEE82EE);
+      Wheat                = TAlphaColor($ffF5DEB3);
+      WhiteSmoke           = TAlphaColor($ffF5F5F5);
+      Yellow               = TAlphaColor($ffFFFF00);
+      YellowGreen          = TAlphaColor($ff9ACD32);
+  private
+    function GetColor : TAlphaColor;
+    procedure SetColor(aColor : TAlphaColor);
+    function GetHiWord : Word;    
+    function GetLoWord : Word;    
+    procedure SetHiWord(aValue : Word);    
+    procedure SetLoWord(aValue : Word);    
+  public
+    B, G, R, A: Byte;
+    constructor Create(const aColor: TAlphaColor);
+    class var ColorToRGB: function (Color: TAlphaColor): Longint;
+    function ToString : RTLString;
+    property Color: TAlphaColor read GetColor Write SetColor;
+    property HiWord: Word Read GetHiWord Write SetHiWord;
+    property LoWord: Word Read GetLoWord Write SetLoword;
+  end;
+  TAlphaColorRec = TAlphaColors;
+  PAlphaColorRec = ^TAlphaColorRec;
+
+  PAlphaColorF = ^TAlphaColorF;
+  TAlphaColorF = record
+  Public
+    R, G, B, A: Single;
+  const
+    Epsilon = 1.5259E-05; // 1 / 65535, minimal value for TPixelFormat.RGBA16 components
+
+    class function Create(const R, G, B: Single; const A: Single = 1): TAlphaColorF; overload; static; inline;
+    class function Create(const aColor: TAlphaColor): TAlphaColorF; overload; static; inline;
+
+    function PremultipliedAlpha: TAlphaColorF;
+    function UnpremultipliedAlpha: TAlphaColorF;
+
+    function Clamp: TAlphaColorF;
+    function ToAlphaColor: TAlphaColor;
+  end;
+
+  { TColorHelper }
+
+  TColorHelper = record helper for TColor
+    Function ToString : RTLString;
+  end;
+
+
+// copied from Lazutils version
+///////////////////////////////
+
+type
+  // Message dialog related
+  TMsgDlgType    = (mtWarning, mtError, mtInformation, mtConfirmation, mtCustom);
+  TMsgDlgBtn     = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore,
+                    mbAll, mbNoToAll, mbYesToAll, mbHelp, mbClose);
+  TMsgDlgButtons = set of TMsgDlgBtn;
+
+  // ModalResult
+  TModalResult = low(Integer)..high(Integer);
+
+const
+  // Used for ModalResult
+  mrNone = 0;
+  mrOK = mrNone + 1;
+  mrCancel = mrNone + 2;
+  mrAbort = mrNone + 3;
+  mrRetry = mrNone + 4;
+  mrIgnore = mrNone + 5;
+  mrYes = mrNone + 6;
+  mrNo = mrNone + 7;
+  mrAll = mrNone + 8;
+  mrNoToAll = mrNone + 9;
+  mrYesToAll = mrNone + 10;
+  mrClose = mrNone + 11;
+  mrContinue = mrNone + 12;
+  mrTryAgain = mrNone + 13;
+  mrLast = mrTryAgain;
+  
+  // String representation of ModalResult values
+  ModalResultStr: array[mrNone..mrLast] of string = (
+    'mrNone',
+    'mrOk',
+    'mrCancel',
+    'mrAbort',
+    'mrRetry',
+    'mrIgnore',
+    'mrYes',
+    'mrNo',
+    'mrAll',
+    'mrNoToAll',
+    'mrYesToAll',
+    'mrClose',
+    'mrContinue',
+    'mrTryAgain');
+
+// CONTROLS
+type
+  TCloseAction = (caNone, caHide, caFree, caMinimize);
+  TCloseActions = set of  TCloseAction;
+  
+  TMouseButton = (mbLeft, mbRight, mbMiddle, mbExtra1, mbExtra2);
+  TMouseButtons = set of TMouseButton;
+  
+  TTabOrder = -1..32767;
+  
+  TDragKind = (dkDrag, dkDock);
+  TDragKinds = set of TDragKind;
+  
+  TDragMode = (dmManual , dmAutomatic);
+  TDragModes = set of TDragMode;
+  
+  TDragState = (dsDragEnter, dsDragLeave, dsDragMove);
+  TDragStates = set of TDragState;
+  
+  TDragMessage = (dmDragEnter, dmDragLeave, dmDragMove, dmDragDrop,
+                  dmDragCancel,dmFindTarget);
+  TDragMessages = set of TDragMessage;
+
+  TAnchorKind = (akTop, akLeft, akRight, akBottom);
+  TAnchors = set of TAnchorKind;
+  TAnchorKinds = TAnchors;
+
+  TAnchorSideReference = (asrTop, asrBottom, asrCenter);
+  TAnchorSideReferences = set of TAnchorSideReference;
+
+  TScrollCode = (scLineUp, scLineDown, scPageUp, scPageDown, scPosition,
+                scTrack, scTop, scBottom, scEndScroll);
+  TScrollCodes = set of TScrollCode;
+  
+  TCursor = SmallInt; // -32768..32767;
+
+const
+  // Cursor constants
+  crHigh        = TCursor(0);
+  crDefault     = TCursor(0);
+  crNone        = TCursor(-1);
+  crArrow       = TCursor(-2);
+  crCross       = TCursor(-3);
+  crIBeam       = TCursor(-4);
+  crSize        = TCursor(-22);
+  crSizeNESW    = TCursor(-6); // diagonal north east - south west
+  crSizeNS      = TCursor(-7);
+  crSizeNWSE    = TCursor(-8);
+  crSizeWE      = TCursor(-9);
+  crSizeNW      = TCursor(-23);
+  crSizeN       = TCursor(-24);
+  crSizeNE      = TCursor(-25);
+  crSizeW       = TCursor(-26);
+  crSizeE       = TCursor(-27);
+  crSizeSW      = TCursor(-28);
+  crSizeS       = TCursor(-29);
+  crSizeSE      = TCursor(-30);
+  crUpArrow     = TCursor(-10);
+  crHourGlass   = TCursor(-11);
+  crDrag        = TCursor(-12);
+  crNoDrop      = TCursor(-13);
+  crHSplit      = TCursor(-14);
+  crVSplit      = TCursor(-15);
+  crMultiDrag   = TCursor(-16);
+  crSQLWait     = TCursor(-17);
+  crNo          = TCursor(-18);
+  crAppStart    = TCursor(-19);
+  crHelp        = TCursor(-20);
+  crHandPoint   = TCursor(-21);
+  crSizeAll     = TCursor(-22);
+  crLow         = TCursor(-30);
+
+
+  // font types&styles
+  LF_FULLFACESIZE = 64;
+  LF_FACESIZE = 32;
+
+type
+  TFontPitch = (fpDefault, fpVariable, fpFixed);
+  TFontName = string;
+  TFontDataName = string; // [LF_FACESIZE -1];
+  TFontStyle = (fsBold, fsItalic, fsUnderline, fsStrikeOut);
+  TFontStyles = set of TFontStyle;
+  TFontStylesBase = set of TFontStyle;
+  TFontCharSet = 0..255;
+  TFontQuality = (fqDefault, fqDraft, fqProof, fqNonAntialiased, fqAntialiased,
+    fqCleartype, fqCleartypeNatural);
+
+// PRINTERS
+  TPrinterOrientation = (poPortrait,poLandscape,poReverseLandscape,poReversePortrait);
+  TPrinterOrientations = set of TPrinterOrientation;
+  
+  TPrinterCapability  = (pcCopies, pcOrientation, pcCollation);
+  TPrinterCapabilities= Set of TPrinterCapability;
+  
+  TPrinterState = (psNoHandle, psHandleIC, psHandleDC);
+  TPrinterStates = set of TPrinterState;
+  
+
+// Gestures
+const
+  sgiNoGesture       =  0;
+  sgiLeft            =  1;
+  sgiRight           =  2;
+  sgiUp              =  3;
+  sgiDown            =  4;
+  sgiUpLeft          =  5;
+  sgiUpRight         =  6;
+  sgiDownLeft        =  7;
+  sgiDownRight       =  8;
+  sgiLeftUp          =  9;
+  sgiLeftDown        = 10;
+  sgiRightUp         = 11;
+  sgiRightDown       = 12;
+  sgiUpDown          = 13;
+  sgiDownUp          = 14;
+  sgiLeftRight       = 15;
+  sgiRightLeft       = 16;
+  sgiUpLeftLong      = 17;
+  sgiUpRightLong     = 18;
+  sgiDownLeftLong    = 19;
+  sgiDownRightLong   = 20;
+  sgiScratchout      = 21;
+  sgiTriangle        = 22;
+  sgiSquare          = 23;
+  sgiCheck           = 24;
+  sgiCurlicue        = 25;
+  sgiDoubleCurlicue  = 26;
+  sgiCircle          = 27;
+  sgiDoubleCircle    = 28;
+  sgiSemiCircleLeft  = 29;
+  sgiSemiCircleRight = 30;
+  sgiChevronUp       = 31;
+  sgiChevronDown     = 32;
+  sgiChevronLeft     = 33;
+  sgiChevronRight    = 34;
+  
+  sgiFirst           = sgiLeft;
+  sgiLast            = sgiChevronRight;
+
+  // ID range for custom gestures 
+ 
+  cgiFirst = -512;
+  cgiLast  = -1;
+
+  // Range for registered custom gestures
+  rgiFirst = -1024;
+  rgiLast  = -513;
+
+  // Interactive gesture ID range.
+  igiFirst = 256;
+  igiLast  = 511;
+
+const
+  // Interactive gesture IDs
+  igiBegin         = igiFirst + 1;
+  igiEnd           = igiFirst + 2;
+  igiZoom          = igiFirst + 3;
+  igiPan           = igiFirst + 4;
+  igiRotate        = igiFirst + 5;
+  igiTwoFingerTap  = igiFirst + 6;
+  igiPressAndTap   = igiFirst + 7;
+  igiLongTap       = igiFirst + 8;
+  igiDoubleTap     = igiFirst + 9;
+
+const
+  { Virtual keys }
+  vkLButton          = $01;  
+  vkRButton          = $02;  
+  vkCancel           = $03;  
+  vkMButton          = $04;  
+  vkXButton1         = $05;  
+  vkXButton2         = $06;  
+  vkBack             = $08;  
+  vkTab              = $09;  
+  vkLineFeed         = $0A;  
+  vkClear            = $0C;  
+  vkReturn           = $0D;  
+  vkShift            = $10;  
+  vkControl          = $11;  
+  vkMenu             = $12;  
+  vkPause            = $13;  
+  vkCapital          = $14;  
+  vkKana             = $15;  
+  vkHangul           = $15;  
+  vkJunja            = $17;  
+  vkFinal            = $18;  
+  vkHanja            = $19;  
+  vkKanji            = $19;  
+  vkConvert          = $1C;  
+  vkNonConvert       = $1D;  
+  vkAccept           = $1E;  
+  vkModeChange       = $1F;  
+  vkEscape           = $1B;  
+  vkSpace            = $20;  
+  vkPrior            = $21;  
+  vkNext             = $22;  
+  vkEnd              = $23;  
+  vkHome             = $24;  
+  vkLeft             = $25;  
+  vkUp               = $26;  
+  vkRight            = $27;  
+  vkDown             = $28;  
+  vkSelect           = $29;  
+  vkPrint            = $2A;  
+  vkExecute          = $2B;  
+  vkSnapshot         = $2C;  
+  vkInsert           = $2D;  
+  vkDelete           = $2E;  
+  vkHelp             = $2F;  
+
+  vk0                = $30;  
+  vk1                = $31;  
+  vk2                = $32;  
+  vk3                = $33;  
+  vk4                = $34;  
+  vk5                = $35;  
+  vk6                = $36;  
+  vk7                = $37;  
+  vk8                = $38;  
+  vk9                = $39;  
+  vkLCommand         = $3D;  
+  vkRCommand         = $3E;  
+  vkFunction         = $3F;  
+
+  vkA                = $41;  
+  vkB                = $42;  
+  vkC                = $43;  
+  vkD                = $44;  
+  vkE                = $45;  
+  vkF                = $46;  
+  vkG                = $47;  
+  vkH                = $48;  
+  vkI                = $49;  
+  vkJ                = $4A;  
+  vkK                = $4B;  
+  vkL                = $4C;  
+  vkM                = $4D;  
+  vkN                = $4E;  
+  vkO                = $4F;  
+  vkP                = $50;  
+  vkQ                = $51;  
+  vkR                = $52;  
+  vkS                = $53;  
+  vkT                = $54;  
+  vkU                = $55;  
+  vkV                = $56;  
+  vkW                = $57;  
+  vkX                = $58;  
+  vkY                = $59;  
+  vkZ                = $5A;  
+  vkLWin             = $5B;  
+  vkRWin             = $5C;  
+  vkApps             = $5D;  
+  vkSleep            = $5F;  
+  vkNumpad0          = $60;  
+  vkNumpad1          = $61;  
+  vkNumpad2          = $62;  
+  vkNumpad3          = $63;  
+  vkNumpad4          = $64;  
+  vkNumpad5          = $65;  
+  vkNumpad6          = $66;  
+  vkNumpad7          = $67;  
+  vkNumpad8          = $68;  
+  vkNumpad9          = $69;  
+  vkMultiply         = $6A;  
+  vkAdd              = $6B;  
+  vkSeparator        = $6C;  
+  vkSubtract         = $6D;  
+  vkDecimal          = $6E;  
+  vkDivide           = $6F;  
+  vkF1               = $70;  
+  vkF2               = $71;  
+  vkF3               = $72;  
+  vkF4               = $73;  
+  vkF5               = $74;  
+  vkF6               = $75;  
+  vkF7               = $76;  
+  vkF8               = $77;  
+  vkF9               = $78;  
+  vkF10              = $79;  
+  vkF11              = $7A;  
+  vkF12              = $7B;  
+  vkF13              = $7C;  
+  vkF14              = $7D;  
+  vkF15              = $7E;  
+  vkF16              = $7F;  
+  vkF17              = $80;  
+  vkF18              = $81;  
+  vkF19              = $82;  
+  vkF20              = $83;  
+  vkF21              = $84;  
+  vkF22              = $85;  
+  vkF23              = $86;  
+  vkF24              = $87;  
+
+  vkCamera           = $88;  
+  vkHardwareBack     = $89;  
+
+  vkNumLock          = $90;  
+  vkScroll           = $91;  
+  vkLShift           = $A0;  
+  vkRShift           = $A1;  
+  vkLControl         = $A2;  
+  vkRControl         = $A3;  
+  vkLMenu            = $A4;  
+  vkRMenu            = $A5;  
+
+  vkBrowserBack      = $A6;  
+  vkBrowserForward   = $A7;  
+  vkBrowserRefresh   = $A8;  
+  vkBrowserStop      = $A9;  
+  vkBrowserSearch    = $AA;  
+  vkBrowserFavorites = $AB;  
+  vkBrowserHome      = $AC;  
+  vkVolumeMute       = $AD;  
+  vkVolumeDown       = $AE;  
+  vkVolumeUp         = $AF;  
+  vkMediaNextTrack   = $B0;  
+  vkMediaPrevTrack   = $B1;  
+  vkMediaStop        = $B2;  
+  vkMediaPlayPause   = $B3;  
+  vkLaunchMail       = $B4;  
+  vkLaunchMediaSelect= $B5;  
+  vkLaunchApp1       = $B6;  
+  vkLaunchApp2       = $B7;  
+
+  vkSemicolon        = $BA;  
+  vkEqual            = $BB;  
+  vkComma            = $BC;  
+  vkMinus            = $BD;  
+  vkPeriod           = $BE;  
+  vkSlash            = $BF;  
+  vkTilde            = $C0;  
+  vkLeftBracket      = $DB;  
+  vkBackslash        = $DC;  
+  vkRightBracket     = $DD;  
+  vkQuote            = $DE;  
+  vkPara             = $DF;  
+
+  vkOem102           = $E2;  
+  vkIcoHelp          = $E3;  
+  vkIco00            = $E4;  
+  vkProcessKey       = $E5;  
+  vkIcoClear         = $E6;  
+  vkPacket           = $E7;  
+  vkAttn             = $F6;  
+  vkCrsel            = $F7;  
+  vkExsel            = $F8;  
+  vkErEof            = $F9;  
+  vkPlay             = $FA;  
+  vkZoom             = $FB;  
+  vkNoname           = $FC;  
+  vkPA1              = $FD;  
+  vkOemClear         = $FE;  
+  vkNone             = $FF;  
+
+// Edit controls
+
+Type
+  TEditCharCase = (ecNormal, ecUpperCase, ecLowerCase);
+  
+  TTouchTracking = set of (ttVertical, ttHorizontal);
+  
+  // Forms
+  
+  TWindowState = (wsNormal, wsMinimized, wsMaximized, wsFullScreen);
+  TWindowStates = Set of TWindowState;
+  
+  TBorderIcon = (biSystemMenu, biMinimize, biMaximize, biHelp);
+  TBorderIcons = set of TBorderIcon;
+    
+  // Dialogs
+  TOpenOption = (ofReadOnly, ofOverwritePrompt, ofHideReadOnly,
+    ofNoChangeDir, ofShowHelp, ofNoValidate, ofAllowMultiSelect,
+    ofExtensionDifferent, ofPathMustExist, ofFileMustExist, ofCreatePrompt,
+    ofShareAware, ofNoReadOnlyReturn, ofNoTestFileCreate, ofNoNetworkButton,
+    ofNoLongNames, ofOldStyleDialog, ofNoDereferenceLinks, ofEnableIncludeNotify,
+    ofEnableSizing, ofDontAddToRecent, ofForceShowHidden);
+  TOpenOptions = set of TOpenOption;
+
+  TOpenOptionEx = (ofExNoPlacesBar);
+  TOpenOptionsEx = set of TOpenOptionEx;
+
+  TDialogType = (Standard, Directory);
+
+  TPrintRange = (prAllPages, prSelection, prPageNums);
+  TPrintDialogOption = (poPrintToFile, poPageNums, poSelection, poWarning,
+    poHelp, poDisablePrintToFile);
+  TPrintDialogOptions = set of TPrintDialogOption;
+  TPageType = (ptEnvelope, ptPaper);
+  TPageTypes = set of TPageType;
+
+  TPageSetupDialogOption = (psoDefaultMinMargins, psoDisableMargins,
+      psoDisableOrientation, psoDisablePagePainting, psoDisablePaper, psoDisablePrinter,
+      psoMargins, psoMinMargins, psoShowHelp, psoWarning, psoNoNetworkButton);
+    TPageSetupDialogOptions = set of TPageSetupDialogOption;
+
+  TPageMeasureUnits = (pmDefault, pmMillimeters, pmInches);
+
+  TCalDayOfWeek = (dowMonday, dowTuesday, dowWednesday, dowThursday,
+    dowFriday, dowSaturday, dowSunday, dowLocaleDefault);
+
+function IsPositiveResult(const AModalResult: TModalResult): Boolean;
+function IsNegativeResult(const AModalResult: TModalResult): Boolean;
+function IsAbortResult(const AModalResult: TModalResult): Boolean;
+function IsAnAllResult(const AModalResult: TModalResult): Boolean;
+function StripAllFromResult(const AModalResult: TModalResult): TModalResult;
+
+
+implementation
+
+function IsPositiveResult(const AModalResult: TModalResult): Boolean;
+
+begin
+  Result:=aModalResult in [mrOk,mrYes,mrAll,mrYesToAll,mrContinue]
+end;
+
+
+function IsNegativeResult(const AModalResult: TModalResult): Boolean;
+
+begin
+  Result:=aModalResult in [mrNo,mrNoToAll,mrTryAgain]
+end;
+
+
+function IsAbortResult(const AModalResult: TModalResult): Boolean;
+
+begin
+   Result:=aModalResult in [mrCancel,mrAbort]
+end;
+
+
+function IsAnAllResult(const AModalResult: TModalResult): Boolean;
+
+begin
+  Result:=aModalResult in [mrAll,mrNoToAll,mrYesToAll]
+end;
+
+
+function StripAllFromResult(const AModalResult: TModalResult): TModalResult;
+
+begin
+  case aModalResult of
+  mrAll:
+    Result:=mrOk;
+  mrNoToAll:
+    Result:=mrNo;
+  mrYesToAll: 
+    Result:=mrYes;
+  else
+    Result:=aModalResult;
+  end;
+end;
+
+
+function TColorRec.ToString: RTLString;
+
+var
+  S : string;
+
+begin
+  if (Self.Color and $FF000000)=$FF then
+    Result:='SYS '+HexStr(Self.Color and $00FFFFFF,6)
+  else
+    Result:='#'+HexStr(R,2)+HexStr(G,2)+HexStr(B,2)
+end;
+
+constructor TAlphaColors.Create(const aColor: TAlphaColor);
+begin
+  color:=aColor;
+end;
+
+function TAlphaColors.ToString: RTLString;
+begin
+  Result:='#'+HexStr(R,2)+HexStr(G,2)+HexStr(B,2)+HexStr(A,2)
+end;
+
+
+class function TAlphaColorF.Create(const R, G, B: Single; const A: Single = 1): TAlphaColorF; overload; static; 
+
+begin
+  Result.A:=A;
+  Result.R:=R;
+  Result.G:=G;
+  Result.B:=B;
+end;
+
+
+class function TAlphaColorF.Create(const aColor: TAlphaColor): TAlphaColorF; overload; static; 
+
+  function ToSingle(aCom : Byte) : single; inline;
+  begin
+    Result:=aCom/255;
+  end;
+  
+var
+  CR : TAlphaColorRec absolute aColor;  
+
+begin
+  Result.A:=ToSingle(CR.A);
+  Result.R:=ToSingle(CR.R);
+  Result.G:=ToSingle(CR.G);
+  Result.B:=ToSingle(CR.B);
+end;
+
+
+function TAlphaColorF.PremultipliedAlpha: TAlphaColorF;
+
+begin
+  Result.A:=A;
+  Result.R:=A*R;
+  Result.G:=A*G;
+  Result.B:=A*B;
+end;
+
+
+function TAlphaColorF.UnpremultipliedAlpha: TAlphaColorF;
+
+var
+  F : Single;
+  
+begin
+  Result.A:=A;
+  if A<Epsilon then
+    F:=0
+  else if Abs(A-1)<Epsilon then
+    F:=1
+  else
+    F:=1/A;
+  Result.R:=F*R;
+  Result.G:=F*G;
+  Result.B:=F*B;
+end;
+
+
+
+function TAlphaColorF.Clamp: TAlphaColorF;
+
+  function Limit(C :Single) : Single; inline;
+  
+  begin
+    if C>1 then
+      Result:=1
+    else if C<0 then
+      Result:=0
+    else
+      Result:=C;
+  end;    
+
+begin
+  Result.A:=Limit(A);  
+  Result.R:=Limit(R);  
+  Result.G:=Limit(G);  
+  Result.B:=Limit(B);  
+end;
+
+
+function TAlphaColorF.ToAlphaColor: TAlphaColor;
+
+  Function CC(C : Single) : Byte; inline;
+  
+  begin
+    Result:=Round(C*255);
+  end;
+
+var
+  CR : TAlphaColorRec absolute Result;
+
+begin
+  CR.A:=CC(A);
+  CR.R:=CC(R);
+  CR.G:=CC(G);
+  CR.B:=CC(B);
+end;
+
+{ TColorHelper }
+
+function TColorHelper.ToString: RTLString;
+var
+  c : TColorRec;
+begin
+  C.color:=Self;
+  Result:=C.ToString;
+end;
+
+function DefaultColorToRGB(Color: TColor): Longint;
+begin
+  Result:=Color;
+end;
+
+function TColorRec.GetColor : TColor;
+begin
+  Result:=(B shl 16) or (G shl 8) or R;
+end;
+
+procedure TColorRec.SetColor(aColor : TColor);
+begin
+  R := aColor and $FF;
+  aColor:=aColor shr 8;
+  G := (aColor and $FF);
+  aColor:=aColor shr 8;
+  B := (aColor and $FF);
+  aColor:=aColor shr 8;
+  A := 0;
+end;
+
+function TAlphaColors.GetColor : TAlphaColor;
+
+begin
+//      B, G, R, A: Byte;
+  Result:=(B shl 24) or (G shl 16) or (R shl 8) or A;
+  
+end;
+
+procedure TAlphaColors.SetColor(aColor : TAlphaColor);
+
+begin
+  B := (aColor and $FF);
+  aColor:=aColor shr 8;
+  G := (aColor and $FF);
+  aColor:=aColor shr 8;
+  R := (aColor and $FF);
+  aColor:=aColor shr 8;
+  A := (aColor and $FF);
+end;
+
+function TAlphaColors.GetHiWord : Word;    
+
+begin
+  Result:=(B shl 8) or G;
+end;
+
+function TAlphaColors.GetLoWord : Word;    
+
+begin
+  Result:=(R shl 8) or A
+end;
+
+procedure TAlphaColors.SetHiWord(aValue : Word);    
+
+begin
+  G:=(aValue or $FF);
+  aValue:=aValue shr 8;
+  B:=(aValue or $FF);
+end;
+
+procedure TAlphaColors.SetLoWord(aValue : Word);    
+
+begin
+  R:=(aValue or $FF);
+  aValue:=aValue shr 8;
+  A:=(aValue or $FF);
+end;
+
+initialization
+  TColorRec.ColorToRGB:=@DefaultColorToRGB;
+end.

+ 36 - 1
packages/rtl/src/web.pas

@@ -134,6 +134,7 @@ Type
   TJSImageBitmap = BrowserApi.WebOrWorker.TJSImageBitmap;
   TJSOffscreenCanvasRenderingContext2D = BrowserApi.WebOrWorker.TJSOffscreenCanvasRenderingContext2D;
   TJSHTMLOffscreenCanvasElement = BrowserApi.WebOrWorker.TJSHTMLOffscreenCanvas;
+  TJSHTMLOffscreenCanvas = BrowserApi.WebOrWorker..TJSHTMLOffscreenCanvas;
 {$ELSE}
   TJSServiceWorker = weborworker.TJSServiceWorker;
   TJSServiceWorkerRegistration = weborworker.TJSServiceWorkerRegistration;
@@ -214,6 +215,7 @@ Type
   TJSImageBitmap = weborworker.TJSImageBitmap;
   TJSOffscreenCanvasRenderingContext2D = weborworker.TJSOffscreenCanvasRenderingContext2D;
   TJSHTMLOffscreenCanvasElement = weborworker.TJSHTMLOffscreenCanvas;
+  TJSHTMLOffscreenCanvas = weborworker.TJSHTMLOffscreenCanvas;
 {$ENDIF}
   TJSMessagePortArray = TJSMessagePortDynArray;
   TEventListenerEvent = TJSEvent;
@@ -2613,6 +2615,7 @@ Type
     Function getContext(contextType : string; contextAttributes : TJSObject) : TJSObject;
     Function getContextAs2DContext(contextType : string; contextAttributes : TJSObject) : TJSCanvasRenderingContext2D; external name 'getContext';
     Function getContextAs2DContext(contextType : string) : TJSCanvasRenderingContext2D; external name 'getContext';
+    Function getContextAsImageBitmapContext(contextType : string) : TJSImageBitmapCanvasRenderingContext; external name 'getContext'; reintroduce;
     Procedure toBlob (aCallBack : THTMLCanvasToBlobCallback; aMimeType : String); overload;
     Procedure toBlob (aCallBack : THTMLCanvasToBlobCallback; aMimeType : String; aQuality : Double); overload;
     Function toDataURL : String; overload;
@@ -2871,7 +2874,39 @@ Type
     Property deltaMode : NativeInt Read FDeltaMode;
   end;
 
-  TJSPointerEvent = Class external name 'PointerEvent' (TJSMouseEvent);
+  { TJSPointerEvent }
+
+  TJSPointerEvent = Class external name 'PointerEvent' (TJSMouseEvent)
+  private
+    faltitudeAngle : double; external name 'altitudeAngle';
+    fazimuthAngle : double; external name 'azimuthAngle';
+    fheight : integer; external name 'height';
+    fisPrimary : boolean; external name 'isPrimary';
+    fpersistentDeviceId : NativeInt; external name 'persistentDeviceId';
+    fPointerID : NativeInt; external name 'pointerId';
+    fPointerType : string; external name 'pointerType';
+    fpressure : double; external name 'pressure';
+    ftangentialpressure : double; external name 'tangentialPressure';
+    fTiltX : double; external name 'tiltX';
+    fTiltY : double; external name 'tiltY';
+    fTwist : nativeint; external name 'twist';
+    fWidth : nativeint; external name 'width';
+  public
+    property altitudeAngle : double read FaltitudeAngle;
+    property azimuthAngle : double read FazimuthAngle;
+    property height: integer read fheight;
+    property isPrimary : boolean read FisPrimary;
+    property persistentDeviceId : NativeInt read FpersistentDeviceId;
+    property pointerId : NativeInt read FPointerID;
+    property pointerType : string read FPointerType;
+    property pressure : double read fpressure;
+    property tangentialPressure : double read ftangentialpressure;
+    property tiltX : double read FTiltX;
+    property tiltY : double read FTiltY;
+    property twist : nativeint read FTwist;
+    property width : nativeint read FWidth;
+
+  end;
 
   TJSTouchEvent = Class external name 'TouchEvent'(TJSUIEvent)
   private

+ 18 - 0
packages/rtl/src/webassembly.pas

@@ -41,11 +41,19 @@ Type
   TJSWebAssemblyMemory = class external name 'WebAssembly.Memory' (TJSObject)
   private
     FBuffer: TJSArrayBuffer; external name 'buffer';
+    FSharedBuffer: TJSSharedArrayBuffer; external name 'buffer';
   Public
     constructor new (memorydescriptor : TJSWebAssemblyMemoryDescriptor);
     constructor new (memorydescriptor : TJSObject);
     Function grow(number : NativeInt) : NativeInt; external name 'grow';
     Property buffer : TJSArrayBuffer Read FBuffer;
+    Property Sharedbuffer : TJSSharedArrayBuffer Read FSharedBuffer;
+  end;
+
+  { TJSWebAssemblyMemoryHelper }
+
+  TJSWebAssemblyMemoryHelper = class helper for TJSWebAssemblyMemory
+    function IsSharedBuffer : Boolean;
   end;
 
   { TJSModulesArray }
@@ -129,5 +137,15 @@ Type
 
 implementation
 
+{ TJSWebAssemblyMemoryHelper }
+
+function TJSWebAssemblyMemoryHelper.IsSharedBuffer: Boolean;
+begin
+  asm
+  return ((!(buffer === null)) && (typeof this.FBuffer === 'object'))
+          && (this.FBuffer instanceof SharedArrayBuffer);
+  end;
+end;
+
 end.
 

+ 302 - 5
packages/rtl/src/weborworker.pas

@@ -58,6 +58,8 @@ type
   NotificationPermission = String;
   NotificationDirection = String;
   NotificationPermissionCallback = Procedure (permission : NotificationPermission);
+  TJSHTMLOffscreenCanvas = class;
+  TJSOffscreenCanvasRenderingContext2D = class;
 
 
   TJSFileSystemFileHandleArray = array of TJSFileSystemFileHandle;
@@ -1677,6 +1679,7 @@ type
     FstrokeStylePattern: TJSCanvasPattern; external name 'strokeStyle';
   Public
     fillStyle : JSValue;
+    filter : string;
     font : string;
     globalAlpha : double;
     globalCompositeOperation : String;
@@ -1761,9 +1764,7 @@ type
     property strokeStyleAsPattern : TJSCanvasPattern Read FstrokeStylePattern Write FstrokeStylePattern;
   end;
 
-  TJSCanvasRenderingContext2D = class external name 'CanvasRenderingContext2D'(TJSBaseCanvasRenderingContext2D)
-  end;
-
+  TJSCanvasRenderingContext2D = class external name 'CanvasRenderingContext2D'(TJSBaseCanvasRenderingContext2D);
 
   { TJSImageBitmap }
 
@@ -1777,15 +1778,25 @@ type
     property height : cardinal read FHeight;
   end;
 
-  TJSOffscreenCanvasRenderingContext2D = class;
+
+  TJSImageBitmapCanvasRenderingContext = class external name 'ImageBitmapRenderingContext'  (TJSBaseCanvasRenderingContext2D)
+    procedure transferFromImageBitmap(aBitmap : TJSImageBitmap);
+  private
+    FCanvas: TJSHTMLOffscreenCanvas; external name 'canvas';
+  public
+    property canvas : TJSHTMLOffscreenCanvas Read FCanvas;
+  end;
+
+
 
   TJSHTMLOffscreenCanvas = Class external name 'OffscreenCanvas' (TJSObject)
   Public
     constructor New(x,y : Cardinal); overload;
     Function getContext(contextType : string; contextAttributes : TJSObject) : JSValue;
     Function getContext(contextType : string) : JSValue;
-    Function getContextAs2DContext(contextType : string; contextAttributes : TJSObject) : TJSOffscreenCanvasRenderingContext2D; external name 'getContext'; reintroduce;
     Function getContextAs2DContext(contextType : string) : TJSOffscreenCanvasRenderingContext2D; external name 'getContext'; reintroduce;
+    Function getContextAs2DContext(contextType : string; contextAttributes : TJSObject) : TJSOffscreenCanvasRenderingContext2D; external name 'getContext'; reintroduce;
+    Function getContextAsImageBitmapContext(contextType : string) : TJSImageBitmapCanvasRenderingContext; external name 'getContext'; reintroduce;
     function transferToImageBitmap: TJSImageBitmap;
     height : Integer;
     width : Integer;
@@ -1798,6 +1809,262 @@ type
     property canvas : TJSHTMLOffscreenCanvas Read FCanvas;
   end;
 
+
+  { TJSMessageChannel }
+
+  TJSMessageChannel = class external name 'MessageChannel' (TJSObject)
+  private
+    FPort1: TJSMessagePort; external name 'port1';
+    FPort2: TJSMessagePort; external name 'port2';
+  Public
+    property port1 : TJSMessagePort read FPort1;
+    property port2 : TJSMessagePort read FPort2;
+  end;
+
+  { TJSVideoChunkMetaData }
+
+  TJSVideoChunkDecoderConfig = class external name 'Object' (TJSObject)
+    codec : string;
+    description : TJSObject;
+    codedWidth : NativeInt;
+    codedHeight : NativeInt;
+    displayAspectWidth : NativeInt;
+    displayAspectHeight : NativeInt;
+    colorSpace : TJSObject;
+    hardwareAcceleration : string;
+    optimizeForLatency : boolean;
+  end;
+  TJSVideoChunkMetaDataSvc = class external name 'Object' (TJSObject)
+    temporalLayerId : NativeInt;
+  end;
+
+  TJSVideoChunkMetaData = class external name 'Object' (TJSObject)
+  private
+    FalphaSideData: TJSObject; external name 'alphaSideData';
+    Fdecoderconfig: TJSVideoChunkDecoderConfig; external name 'decoderConfig';
+    FSvc: TJSVideoChunkMetaDataSvc;  external name 'svc';
+  Public
+    property decoderConfig : TJSVideoChunkDecoderConfig read Fdecoderconfig;
+    property svc : TJSVideoChunkMetaDataSvc Read FSvc;
+    property alphaSideData : TJSObject Read FalphaSideData;
+  end;
+
+  { TDOMRectReadOnly }
+
+  TDOMRectReadOnly = class external name 'DOMRectReadOnly' (TJSObject)
+  private
+    Fbottom: integer; external name 'bottom';
+    Fheight: integer; external name 'height';
+    Fleft: integer; external name 'left';
+    Fright: integer; external name 'right';
+    Ftop: integer; external name 'top';
+    FWidth: integer; external name 'width';
+    Fx: integer; external name 'x';
+    Fy: integer; external name 'y';
+  public
+    property bottom : integer read Fbottom;
+    property height : integer read Fheight;
+    property left : integer read Fleft;
+    property right : integer read Fright;
+    property top : integer read Ftop;
+    property width : integer Read FWidth;
+    property x : integer read Fx;
+    property y : integer read Fy;
+  end;
+
+  TJSVideoColorSpaceOptions = class external name 'Object' (TJSObject)
+    primaries : string;
+    transfer : string;
+    matrix : string;
+    fullrange : boolean;
+  end;
+
+  { TJSVideoColorSpace }
+
+  TJSVideoColorSpace = class external name 'VideoColorSpace' (TJSObject)
+  private
+    FPrimaries: string; external name 'primaties';
+  Public
+    transfer : string;
+    matrix : string;
+    fullrander : boolean;
+    constructor new();
+    constructor new(aOptions : TJSVideoColorSpace);
+    property primaries : string read FPrimaries;
+  end;
+
+  { TJSVideoFrame }
+  TJSVideoFrameOptionsRect  = class external name 'Object' (TJSObject)
+    x,y,width,height : integer;
+  end;
+
+  TJSVideoFrameOptions = class external name 'Object' (TJSObject)
+    duration : integer;
+    timestamp : integer;
+    alpha : string;
+    visibleRect : TJSVideoFrameOptionsRect;
+    displayWidth : integer;
+    displayHeight : integer;
+  end;
+
+  TJSVideoFrame = class external name 'VideoFrame' (TJSObject)
+  private
+    FcodedHeight: NativeInt; external name 'codedHeight';
+    FcodedRect: TDOMRectReadOnly; external name 'codedRect';
+    FcodedWidth: NativeInt; external name 'codedWidth';
+    FcolorSpace: TJSVideoColorSpace; external name 'colorSpace';
+    FdisplayHeight: NativeInt; external name 'displayHeight';
+    FdisplayWidth: NativeInt; external name 'displayWidth';
+    Fduration: NativeInt; external name 'duration';
+    Fformat: string; external name 'format';
+    Ftimestamp: NativeInt; external name 'timestamp';
+    FvisibleRect: TDOMRectReadOnly; external name 'visibleRect';
+  Public
+    constructor new(aFormat : TJSImageBitmap);
+    constructor new(aFormat : TJSVideoFrame);
+    constructor new(aFormat : TJSHTMLOffscreenCanvas);
+    constructor new(aFormat : TJSObject);
+    constructor new(aFormat : TJSImageBitmap; aOptions : TJSVideoFrameOptions);
+    constructor new(aFormat : TJSVideoFrame; aOptions : TJSVideoFrameOptions);
+    constructor new(aFormat : TJSHTMLOffscreenCanvas; aOptions : TJSVideoFrameOptions);
+    constructor new(aFormat : TJSObject; aOptions : TJSVideoFrameOptions);
+
+    property format : string read FFormat;
+    property codedHeight : NativeInt Read FcodedHeight;
+    property codedWidth : NativeInt Read FcodedWidth;
+    property codedRect : TDOMRectReadOnly read FcodedRect;
+    property colorSpace : TJSVideoColorSpace read FcolorSpace;
+    property displayHeight : NativeInt read FdisplayHeight;
+    property displayWidth : NativeInt read FdisplayWidth;
+    property duration : NativeInt read Fduration;
+    property timestamp : NativeInt read Ftimestamp;
+    property visibleRect : TDOMRectReadOnly read FvisibleRect;
+  end;
+
+  TJSEncodedVideoChunkOptions = class external name 'Object' (TJSObject)
+    type_ : string; external name 'type';
+    timestamp : NativeInt;
+    duration : NativeInt;
+    data : TJSObject;
+    transfer : TJSObjectDynArray;
+  end;
+
+  { TJSEncodedVideoChunk }
+
+  TJSEncodedVideoChunk = class external name 'EncodedVideoChunk' (TJSObject)
+  private
+    FbyteLength: NativeInt;external name 'byteLength';
+    FDuration: NativeInt;external name 'duration';
+    Ftimestamp: NativeInt;external name 'timestamp';
+    Ftype: string; external name 'type';
+  Public
+    constructor new(aOptions : TJSEncodedVideoChunkOptions);
+    property byteLength : NativeInt Read FbyteLength;
+    property timestamp : NativeInt Read Ftimestamp;
+    property duration : NativeInt Read FDuration;
+    property type_ : string read Ftype;
+  end;
+
+  TVideoEncoderOutputCallBack = reference to procedure (aData : TJSEncodedVideoChunk; aMetaData : TJSVideoChunkMetaData);
+  TVideoEncoderErrorCallBack = reference to procedure (aError: TJSError);
+
+  TJSNewVideoEncoderOptions = class external name 'Object' (TJSObject)
+    output : TVideoEncoderOutputCallBack;
+    error : TVideoEncoderErrorCallBack;
+  end;
+
+  TJSVideoEncoderConfiguration = class external name 'Object' (TJSObject)
+    codec : string;
+    width : NativeInt;
+    height: NativeInt;
+    displayWidth : NativeInt;
+    displayHeight : NativeInt;
+    hardwareAcceleration : string;
+    bitrate : NativeInt;
+    framerate: NativeInt;
+    alpha : string;
+    scalabilityMode : string;
+    bitrateMode : string;
+    latencyMode : string;
+  end;
+
+  TJSVideoEncodeQuantizerOptions = class external name 'Object' (TJSObject)
+    quantizer : Nativeint;
+  end;
+
+  TJSVideoEncodeOptions = class external name 'Object' (TJSObject)
+    keyFrame : boolean;
+    vp9 : TJSVideoEncodeQuantizerOptions;
+    av1 : TJSVideoEncodeQuantizerOptions;
+    avc : TJSVideoEncodeQuantizerOptions;
+    hevc : TJSVideoEncodeQuantizerOptions;
+  end;
+
+  { TJSVideoEncoder }
+
+  TJSVideoEncoder = class external name 'VideoEncoder' (TJSEventTarget)
+  private
+    FencodeQueueSize: NativeInt; external name 'encodeQueueSize';
+    FState: string; external name 'state';
+  Public
+    class function isConfigSupported(aOptions : TJSVideoEncoderConfiguration) : boolean;
+    constructor new(aOptions : TJSNewVideoEncoderOptions);
+    procedure close;
+    procedure configure(aConfig :TJSVideoEncoderConfiguration);
+    procedure encode(Frame : TJSVideoFrame; aOptions : TJSVideoEncodeOptions);
+    procedure flush;
+    procedure reset;
+    property encodeQueueSize : NativeInt Read FencodeQueueSize;
+    property State : string read FState;
+  end;
+
+  TJSVideoDecoderOutputCallBack = reference to procedure (aData : TJSVideoFrame);
+  TJSVideoDecoderErrorCallBack = reference to procedure (aError: TJSError);
+
+  TJSNewVideoDecoderOptions = class external name 'Object' (TJSObject)
+    output : TJSVideoDecoderOutputCallback;
+    error : TJSVideoDecoderErrorCallback;
+  end;
+
+  TJSVideoDecoderConfiguration = class external name 'Object' (TJSObject)
+    codec : string;
+    codedWidth : NativeInt;
+    codedHeight: NativeInt;
+    displayAspectWidth : NativeInt;
+    displayAspectHeight : NativeInt;
+    colorSpace : TJSVideoColorSpace;
+    hardwareAcceleration : string;
+    optimizeForLatency : Boolean;
+  end;
+
+  { TJSVideoDecoder }
+
+  TJSVideoDecoder = class external name 'VideoDecoder' (TJSEventTarget)
+  private
+    FdecodeQueueSize: NativeInt; external name 'decodeQueueSize';
+    FState: string; external name 'state';
+  public
+    constructor new(aOptions : TJSNewVideoDecoderOptions);
+    class function isConfigSupported(aOptions : TJSVideoDecoderConfiguration) : boolean;
+    procedure close;
+    procedure configure(aConfig :TJSVideoEncoderConfiguration);
+    procedure decode(Frame : TJSEncodedVideoChunk);
+    procedure flush;
+    procedure reset;
+    procedure configure(aConfig :TJSVideoDecoderConfiguration);
+    property decodeQueueSize : NativeInt Read FdecodeQueueSize;
+    property State : string read FState;
+  end;
+
+
+  TJSScriptContext = (jscUnknown,jscMainBrowserThread,jscWebWorker,jscServiceWorker);
+
+
+function isMainBrowserThread: boolean;
+function isWebWorker : boolean;
+function IsServiceWorker :boolean;
+function GetScriptContext : TJSScriptContext;
+
 var
   Console : TJSConsole; external name 'console';
   Crypto: TJSCrypto; external name 'crypto';
@@ -1811,7 +2078,37 @@ var
   function fetch(resource: TJSObject; init: TJSObject): TJSPromise; overload; external name 'fetch';
   function fetch(resource: TJSObject): TJSPromise; overload; external name 'fetch';
 
+
 implementation
 
+function GetScriptContext : TJSScriptContext;
+begin
+  Result:=jscUnknown;
+  if isMainBrowserThread then
+    exit(jscMainBrowserThread);
+  if isWebWorker then
+    exit(jscWebWorker);
+  if IsServiceWorker then
+    exit(jscServiceWorker);
+end;
+
+function isMainBrowserThread: boolean; assembler;
+ asm
+   return (typeof window !== "undefined");
+ end;
+
+function isWebWorker : boolean; assembler;
+
+asm
+  return (typeof DedicatedWorkerGlobalScope !== 'undefined') &&
+         (self instanceof DedicatedWorkerGlobalScope);
+end;
+
+function IsServiceWorker :boolean; assembler;
+
+asm
+  Return (typeof ServiceWorkerGlobalScope !== 'undefined') && (self instanceof ServiceWorkerGlobalScope);
+end;
+
 end.
 

+ 25 - 2
packages/wasi/src/rtl.threadcontroller.pas

@@ -56,6 +56,8 @@ Type
 
   { TThreadController }
   TWasmThreadEvent = procedure (Sender : TObject; aWorker : TWasmThread) of object;
+  TWasmThreadArray = array of TWasmThread;
+  TWasmThreadEnumProc = reference to procedure(aWorker : TWasmThread);
 
   TThreadController = class(TWasmThreadSupport)
   private
@@ -72,8 +74,8 @@ Type
     Function thread_detach(thread_id : longint) : Integer; override;
     Function thread_cancel(thread_id : longint) : Integer; override;
   Protected
-    FIdleWorkers : Array of TWasmThread;
-    FBusyWorkers : Array of TWasmThread;
+    FIdleWorkers : TWasmThreadArray;
+    FBusyWorkers : TWasmThreadArray;
     FThreads : TThreadHash; // ThreadID is key,
     // Handle worker messages. If it is a command, it is set to handlecommand.
     procedure DoWorkerMessage(aEvent: TJSEvent);
@@ -112,6 +114,10 @@ Type
     procedure SendCommandToAllWorkers(aCommand : TWorkerCommand);
     // Send a command to a specific thread. TWorkerCommand has the thread ID.
     procedure SendCommandToThread(aCommand : TWorkerCommand);
+    // Get a list of all thread workers
+    Function GetWebWorkers : TWasmThreadArray;
+    // Enumerate workers
+    Procedure EnumerateWebWorkers(aCallback : TWasmThreadEnumProc);
     // Name of worker script
     Property WorkerScript : String Read FWorkerScript;
     // Initial number of threads, set by constructor
@@ -372,6 +378,23 @@ begin
     W.postMessage(aCommand);
 end;
 
+function TThreadController.GetWebWorkers: TWasmThreadArray;
+begin
+  Result:=Concat(FBusyWorkers,FIdleWorkers);
+end;
+
+procedure TThreadController.EnumerateWebWorkers(aCallback: TWasmThreadEnumProc);
+
+var
+  aThread : TWasmThread;
+
+begin
+  if Not assigned(aCallback) then
+    exit;
+  For aThread in GetWebWorkers do
+    aCallBack(aThread);
+end;
+
 procedure TThreadController.RunTimeOut(aInfo: TThreadInfo; aInterval: Integer);
 
 var

+ 30 - 2
packages/wasi/src/rtl.webthreads.pas

@@ -43,6 +43,7 @@ Const
   cmdLoaded = 'loaded';
   cmdKill = 'kill';
   cmdSpawn = 'spawn';
+  cmdStarted = 'started';
   cmdLoad = 'load';
   cmdRun = 'run';
   cmdExecute = 'execute';
@@ -126,13 +127,14 @@ Type
 
   // Cleanup thread info: put this worker into unusued workers
   TWorkerCleanupCommand = class external name 'Object' (TWorkerCommand)
+    exitstatus : integer;
   end;
 
   { TWorkerCleanupCommandHelper }
 
   TWorkerCleanupCommandHelper = class helper for TWorkerCleanupCommand
     Class function CommandName : string; static;
-    Class function Create(aThreadID : Integer): TWorkerCleanupCommand; static;  reintroduce;
+    class function Create(aThreadID, aExitStatus: Integer): TWorkerCleanupCommand; static; reintroduce;
   end;
 
 
@@ -195,6 +197,7 @@ Type
     Module : TJSWebAssemblyModule;
   end;
 
+
   { TWorkerLoadCommandHelper }
 
   TWorkerLoadCommandHelper = class helper for TWorkerLoadCommand
@@ -202,6 +205,17 @@ Type
     Class function Create(aModule : TJSWebAssemblyModule; aMemory : TJSWebAssemblyMemory): TWorkerLoadCommand; static;reintroduce;
   end;
 
+  TWorkerStartedCommand = class external name 'Object' (TWorkerCommand)
+    StartFunction : string;
+  end;
+
+  { TWorkerStartedCommandHelper }
+
+  TWorkerStartedCommandHelper = class helper for TWorkerStartedCommand
+    Class function CommandName : string; static;
+    Class function Create(aFunction : string): TWorkerStartedCommand; static;reintroduce;
+  end;
+
 
   // Sent by main to worker: run thread procedure
   TWorkerRunCommand = class external name 'Object' (TWorkerCommand)
@@ -386,6 +400,19 @@ begin
   Result.Module:=aModule;
 end;
 
+{ TWorkerStartedCommandHelper }
+
+class function TWorkerStartedCommandHelper.CommandName: string;
+begin
+  result:=cmdStarted;
+end;
+
+class function TWorkerStartedCommandHelper.Create(aFunction: string): TWorkerStartedCommand;
+begin
+  Result:=TWorkerStartedCommand(TWorkerCommand.NewWorker(CommandName));
+  Result.StartFunction:=aFunction;
+end;
+
 { TWorkerSpawnThreadCommandHelper }
 
 class function TWorkerSpawnThreadCommandHelper.CommandName: string;
@@ -445,9 +472,10 @@ begin
   Result:=cmdCleanup
 end;
 
-class function TWorkerCleanupCommandHelper.Create(aThreadID: Integer): TWorkerCleanupCommand;
+class function TWorkerCleanupCommandHelper.Create(aThreadID, aExitStatus: Integer): TWorkerCleanupCommand;
 begin
   Result:=TWorkerCleanupCommand(TWorkerCommand.NewWorker(CommandName,aThreadID));
+  Result.ExitStatus:=aExitStatus;
 end;
 
 { TWorkerConsoleCommandHelper }

+ 3 - 0
packages/wasi/src/wasienv.pas

@@ -41,6 +41,9 @@ Const
   SizeQWord    = SizeUInt64;
 
 type
+  // An address in Webassembly memory
+  TWasmPointer = longint;
+
   TMemBufferArray = Array of TJSUint8Array;
 
   TPreLoadFile = record

+ 24 - 4
packages/wasi/src/wasiworkerthreadhost.pas

@@ -56,7 +56,6 @@ Type
   Private
     Type
       TWorkerState = (wsNeutral, wsLoading, wsLoaded, wsRunWaiting, wsRunning);
-    procedure DoRunThread(aExports: TWASIExports);
   Private
     FState: TWorkerState;
     FCurrentThreadInfo : TThreadinfo;
@@ -65,6 +64,7 @@ Type
     FWasiHost: TWASIThreadHost;
   Protected
     // Incoming messages
+    procedure DoRunThread(aExports: TWASIExports); virtual;
     procedure LoadWasmModule(aCommand: TWorkerLoadCommand); virtual;
     procedure RunWasmModule(aCommand: TWorkerRunCommand); virtual;
     procedure CancelWasmModule(aCommand: TWorkerCancelCommand); virtual;
@@ -94,6 +94,7 @@ Type
     FHost : TWASIHost;
     FSendOutputToBrowser: Boolean;
     FConsoleChannel: TJSBroadcastChannel;
+    FSendOutputToConsole: Boolean;
     function GetAfterStart: TAfterStartEvent;
     function GetBeforeStart: TBeforeStartEvent;
     function GetcPredefinedConsoleInput: TStrings;
@@ -141,6 +142,8 @@ Type
     Property BeforeStart : TBeforeStartEvent Read GetBeforeStart Write SetBeforeStart;
     // Send output to browser window process?
     Property SendOutputToBrowser : Boolean Read FSendOutputToBrowser Write FSendOutputToBrowser;
+    // Send output to console ?
+    Property SendOutputToConsole : Boolean Read FSendOutputToConsole Write FSendOutputToConsole;
     // Default console input
     Property PredefinedConsoleInput : TStrings Read GetcPredefinedConsoleInput Write SetPredefinedConsoleInput;
     // Called when reading from console (stdin). If not set, PredefinedConsoleinput is used.
@@ -190,6 +193,7 @@ Type
   TWorkerThreadControllerApplication = class(TWorkerWASIHostApplication)
   Private
     FThreadSupport : TThreadController;
+    function GetThreadHost: TWASIThreadControllerHost;
   Protected
     function CreateThreadSupport(aEnv: TPas2JSWASIEnvironment): TThreadController; virtual;
     procedure HandleConsoleWrite(Sender: TObject; aOutput: string); virtual;
@@ -201,6 +205,8 @@ Type
   Public
     procedure ShowException(aError: Exception); override;
     property ThreadSupport : TThreadController Read FThreadSupport;
+    property ThreadHost : TWASIThreadControllerHost read GetThreadHost;
+
   end;
 
 function GetJSClassName(aObj : TJSObject) : string;
@@ -402,6 +408,7 @@ Procedure TWorkerThreadSupport.DoRunThread(aExports : TWASIExports);
 Var
   aResult : Integer;
 
+
 begin
   try
     FState:=wsRunning;
@@ -410,6 +417,7 @@ begin
     FState:=wsLoaded;
     if aResult>0 then
       SendConsoleMessage('Thread run function result= %d ',[aResult]);
+    SendCommand(TWorkerCleanupCommand.Create(Self.FCurrentThreadInfo.ThreadID,aResult));
   except
     on E : Exception do
       SendException(E);
@@ -633,6 +641,7 @@ begin
   inherited Create(aOwner);
   FHost:=CreateHost;
   FConsoleChannel:=TJSBroadcastChannel.new(channelConsole);
+  FSendOutputToConsole:=true;
 end;
 
 destructor TWorkerWASIHostApplication.Destroy;
@@ -670,7 +679,10 @@ end;
 
 procedure TWorkerThreadRunnerApplication.HandleConsoleWrite(Sender: TObject; aOutput: string);
 begin
-  ConsoleChannel.postMessage(TWorkerConsoleCommand.Create(aOutput));
+  if SendOutputToConsole then
+    Writeln(aOutput);
+  if SendOutputToBrowser then
+    ConsoleChannel.postMessage(TWorkerConsoleCommand.Create(aOutput));
 end;
 
 function TWorkerThreadRunnerApplication.CreateWorkerThreadSupport(aEnv : TPas2JSWasiEnvironment) : TWorkerThreadSupport;
@@ -842,7 +854,10 @@ end;
 
 procedure TWorkerThreadControllerApplication.HandleConsoleWrite(Sender: TObject; aOutput: string);
 begin
-  FConsoleChannel.postMessage(TWorkerConsoleCommand.Create(aOutput,0));
+  if SendOutputToConsole then
+    Writeln(aOutput);
+  if SendOutputToBrowser then
+    FConsoleChannel.postMessage(TWorkerConsoleCommand.Create(aOutput,0));
 end;
 
 function TWorkerThreadControllerApplication.HandleCustomCommand(aData : TWorkerCommand) : Boolean;
@@ -875,10 +890,15 @@ begin
     end;
 end;
 
+function TWorkerThreadControllerApplication.GetThreadHost: TWASIThreadControllerHost;
+begin
+  Result:=(Host as  TWASIThreadControllerHost)
+end;
+
 function TWorkerThreadControllerApplication.CreateThreadSupport(aEnv : TPas2JSWASIEnvironment) : TThreadController;
 
 begin
-  Result:=TThreadController.Create(aEnv,ThreadRunnerScript,20);
+  Result:=TThreadController.Create(aEnv,ThreadRunnerScript,ThreadCount);
 end;
 
 function TWorkerThreadControllerApplication.CreateHost: TWASIHost;

+ 46 - 0
packages/wasm-utils/src/wasm.pas2js.memutils.pas

@@ -0,0 +1,46 @@
+unit wasm.pas2js.memutils;
+
+{$mode ObjFPC}
+
+interface
+
+uses js, wasienv;
+
+type
+
+  { TWasiMemUtils }
+  TMemoryGrowHandler = reference to procedure(aPages : Integer);
+
+  TWasiMemUtils = class(TImportExtension)
+  private
+    FOnMemoryGrow: TMemoryGrowHandler;
+  Protected
+    procedure MemoryGrowNotification(aPages : integer); virtual;
+  Public
+    procedure FillImportObject(aObject: TJSObject); override;
+    function ImportName: String; override;
+    property OnMemoryGrow : TMemoryGrowHandler Read FOnMemoryGrow Write FOnMemoryGrow;
+  end;
+
+implementation
+
+{ TWasiMemUtils }
+
+procedure TWasiMemUtils.MemoryGrowNotification(aPages: integer);
+begin
+  if assigned(OnMemoryGrow) then
+    OnMemoryGrow(aPages);
+end;
+
+procedure TWasiMemUtils.FillImportObject(aObject: TJSObject);
+begin
+  aObject['wasm_memory_grow_notification']:=@MemoryGrowNotification;
+end;
+
+function TWasiMemUtils.ImportName: String;
+begin
+  Result:='wasmmem';
+end;
+
+end.
+

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