fresnel.pas2js.wasmapi.pp 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523
  1. {$mode objfpc}
  2. {$h+}
  3. {$modeswitch externalclass}
  4. {$DEFINE IMAGE_USEOSC}
  5. unit fresnel.pas2js.wasmapi;
  6. interface
  7. // Define this to disable API Logging altogether
  8. { $DEFINE NOLOGAPICALLS}
  9. uses classes, js, web, webassembly, wasienv, fresnel.wasm.shared;
  10. Const
  11. // These should probably move to weborworker
  12. MOUSE_PRIMARY = 1;
  13. MOUSE_SECONDARY = 2;
  14. MOUSE_AUXILIARY = 4;
  15. MOUSE_EXTRA1 = 8;
  16. MOUSE_EXTRA2 = 16;
  17. Type
  18. TWasmPointer = longint;
  19. TWasmFresnelApi = Class;
  20. TTimerTickCallback = Function (aTimerID : TTimerID; UserData : TWasmPointer) : Boolean;
  21. { TFresnelHelper }
  22. TFresnelHelper = Class
  23. Private
  24. class var _CurrentID : TCanvasID;
  25. Public
  26. Class function FresnelColorToHTMLColor(aColor : TCanvasColor) : string;
  27. Class function FresnelColorToHTMLColor(aRed, aGreen, aBlue, aAlpha: TCanvasColorComponent): string;
  28. class Function MouseButtonToShiftState(aButton: Integer): TShiftStateEnum;
  29. Class Function ShiftStateToInt(aState : TShiftState) : Integer;
  30. Class Function AllocateCanvasID : TCanvasID;
  31. end;
  32. TCanvasEvent = record
  33. CanvasID : TCanvasID;
  34. msg : TCanvasMessageID;
  35. param0 : TCanvasMessageParam;
  36. param1 : TCanvasMessageParam;
  37. param2 : TCanvasMessageParam;
  38. param3 : TCanvasMessageParam;
  39. end;
  40. { TCanvasReference }
  41. TCanvasReference = class (TObject)
  42. API : TWasmFresnelApi;
  43. CanvasID : TCanvasID;
  44. canvascontext : TJSCanvasRenderingContext2D;
  45. canvas :TJSHTMLCanvasElement;
  46. canvasParent :TJSHTMLElement;
  47. constructor create(aID : TCanvasID; aAPI : TWasmFresnelApi; aCanvas : TJSHTMLCanvasElement; aParent : TJSHTMLElement);
  48. private
  49. function DoMouseClick(aEvent: TJSEvent): boolean;
  50. function DoMouseDblClick(aEvent: TJSEvent): boolean;
  51. function DoMouseDown(aEvent: TJSEvent): boolean;
  52. function DoMouseUp(aEvent: TJSEvent): boolean;
  53. function DoMouseMove(aEvent: TJSEvent): boolean;
  54. function DoMouseWheel(aEvent: TJSEvent): boolean;
  55. function MouseToEvent(aEvent: TJSMouseEvent; aMessageID: TCanvasMessageID): TCanvasEvent;
  56. procedure PrepareCanvas;
  57. Procedure RemoveCanvas;
  58. Procedure SendEvent;
  59. end;
  60. { TWasmFresnelApi }
  61. TTimerCallback = Procedure (aCurrent,aPrevious : Double);
  62. TWasmFresnelApi = class(TImportExtension)
  63. Private
  64. FCanvases : TJSObject;
  65. FCanvasParent : TJSHTMLELement;
  66. FLogAPICalls : Boolean;
  67. FTimerID : NativeInt;
  68. FTimerInterval: NativeInt;
  69. FLastTick: TDateTime;
  70. Protected
  71. FEvents : array of TCanvasEvent;
  72. Procedure LogCall(const Msg : String);
  73. Procedure LogCall(Const Fmt : String; const Args : Array of const);
  74. function GetCanvas(aID : TCanvasID) : TJSCanvasRenderingContext2D;
  75. function GetCanvasRef(aID: TCanvasID): TCanvasReference;
  76. // Canvas
  77. function allocatecanvas(SizeX : Longint; SizeY : Longint; aID: TWasmPointer): TCanvasError;
  78. function deallocatecanvas(aID: TCanvasID): TCanvasError;
  79. function getcanvasbyid(aCanvasElementID: TWasmPointer; aElementIDLen: Longint; aID: TWasmPointer): TCanvasError;
  80. function moveto(aID : TCanvasID; X : Longint;Y : Longint): TCanvasError;
  81. function lineto(aID : TCanvasID;X : Longint; Y : Longint ): TCanvasError;
  82. function stroke(aID : TCanvasID): TCanvasError;
  83. function beginpath(aID : TCanvasID): TCanvasError;
  84. function arc(aID : TCanvasID;X : Longint;Y : Longint;RadiusX,RadiusY : Longint;StartAngle : Longint;EndAngle : Longint; Rotate : Longint; Flags : Longint): TCanvasError;
  85. function fillrect(aID : TCanvasID; X : Longint; Y : Longint; Width : Longint; Height : Longint): TCanvasError;
  86. function strokerect(aID : TCanvasID;X : Longint;Y : Longint; Width : Longint; Height : Longint ): TCanvasError;
  87. function clearrect(aID : TCanvasID;X : Longint;Y : Longint;Width : Longint; Height : Longint ): TCanvasError;
  88. function RoundRect(aID : TCanvasID; Flags : Longint; Data : TWasmPointer) : TCanvasError;
  89. function StrokeText(aID : TCanvasID;X : Longint;Y : Longint; aText : TWasmPointer; aTextLen : Longint ): TCanvasError;
  90. function FillText(aID : TCanvasID;X : Longint;Y : Longint; aText : TWasmPointer; aTextLen : Longint ): TCanvasError;
  91. function GetCanvasSizes(aID: TCanvasID; aWidth, aHeight: TWasmPointer): TCanvasError;
  92. function SetFillStyle(aID: TCanvasID; aRed,aGreen,aBlue,aAlpha: TCanvasColorComponent): TCanvasError;
  93. function ClearCanvas(aID: TCanvasID; aRed,aGreen,aBlue,aAlpha: TCanvasColorComponent): TCanvasError;
  94. function SetLinearGradientFillStyle(aID: TCanvasID; aStartX,aStartY,aEndX,aEndY : Longint; aColorPointCount : longint; aColorPoints : TWasmPointer) : TCanvasError;
  95. function SetImageFillStyle(aID: TCanvasID; Flags : Longint; aImageWidth,aImageHeight: Longint; aImageData: TWasmPointer) : TCanvasError;
  96. function SetLineCap(aID: TCanvasID; aCap: TCanvasLinecap): TCanvasError;
  97. function SetLineJoin(aID: TCanvasID; aJoin: TCanvasLineJoin): TCanvasError;
  98. function SetLineMiterLimit(aID: TCanvasID; aWidth: TCanvasLineMiterLimit): TCanvasError;
  99. function SetLineDash(aID: TCanvasID; aOffset : Longint; aPatternCount : longint; aPattern : TWasmPointer): TCanvasError;
  100. function SetLineWidth(aID: TCanvasID; aWidth: TCanvasLineWidth): TCanvasError;
  101. function SetStrokeStyle(aID: TCanvasID; aRed,aGreen,aBlue,aAlpha: TCanvasColorComponent): TCanvasError;
  102. function DrawImage(aID : TCanvasID; aX,aY,aWidth,aHeight,aImageWidth,aImageHeight: Longint; aImageData: TWasmPointer) : TCanvasError;
  103. function SetFont(aID : TCanvasID; aFontName : TWasmPointer; aFontNameLen : integer) : TCanvasError;
  104. function MeasureText(aID : TCanvasID; aText : TWasmPointer; aTextLen : integer; aWidth,aHeight : Longint) : TCanvasError;
  105. function SetTextShadowParams (aID : TCanvasID; aOffsetX,aOffsetY,aRadius : Longint; aRed,aGreen,aBlue,aAlpha : TCanvasColorComponent): TCanvasError;
  106. function DrawPath(aID : TCanvasID; aFlags : Longint; aPathCount : longint; aPath : TWasmPointer) : TCanvasError;
  107. function PointInPath(aID : TCanvasID; aX : Longint; aY : Longint; aPointCount : Integer; aPointData : TWasmPointer; aRes : TWasmPointer): TCanvasError;
  108. function SetTransform(aID : TCanvasID; Flags : Longint; m11,m12,m21,m22,m31,m32 : Longint) : TCanvasError;
  109. // Timer
  110. function AllocateTimer(ainterval : longint; userdata: TWasmPointer) : TTimerID;
  111. procedure DeallocateTimer(timerid: TTimerID);
  112. // Events
  113. function GetEvent(aID: TWasmPointer; aMsg: TWasmPointer; Data : TWasmPointer): TCanvasError;
  114. function GetEventCount(aCount: TWasmPointer): TCanvasError;
  115. procedure DoTimerTick; virtual;
  116. Public
  117. Constructor Create(aEnv : TPas2JSWASIEnvironment); override;
  118. Procedure FillImportObject(aObject : TJSObject); override;
  119. Procedure ProcessMessages;
  120. Procedure StartTimerTick;
  121. Procedure StopTimerTick;
  122. Function ImportName : String; override;
  123. Property CanvasParent : TJSHTMLELement Read FCanvasParent Write FCanvasParent;
  124. Property LogAPICalls : Boolean Read FLogAPICalls Write FLogAPICalls;
  125. Property TimerInterval : NativeInt Read FTimerInterval Write FTimerInterval;
  126. end;
  127. Implementation
  128. uses sysutils;
  129. { ---------------------------------------------------------------------
  130. FresnelHelper
  131. ---------------------------------------------------------------------}
  132. class function TFresnelHelper.FresnelColorToHTMLColor(aRed,aGreen,aBlue,aAlpha: TCanvasColorComponent): string;
  133. begin
  134. Result:='rgb('+inttostr(aRed shr 8)+' '+IntToStr(aGreen shr 8)+' '+inttoStr(aBlue shr 8);
  135. if aAlpha<>$FFFF then
  136. Result:=Result+' / '+floatToStr(aAlpha/255);
  137. Result:=Result+')';
  138. end;
  139. class function TFresnelHelper.FresnelColorToHTMLColor(aColor: TCanvasColor): string;
  140. Const
  141. Hex = '0123456789ABCDEF';
  142. var
  143. I : Integer;
  144. begin
  145. Result:='#';
  146. aColor:=aColor shr 8;
  147. for I:=1 to 6 do
  148. begin
  149. Result:=Result+Hex[(aColor and $F)+1];
  150. aColor:=aColor shr 4;
  151. end;
  152. end;
  153. class Function TFresnelHelper.ShiftStateToInt(aState : TShiftState) : Integer;
  154. var
  155. S : TShiftStateEnum;
  156. begin
  157. Result:=0;
  158. For S in TShiftstate do
  159. If (S in aState) then
  160. Result:=Result or (1 shl Ord(S));
  161. end;
  162. class function TFresnelHelper.MouseButtonToShiftState(aButton : Integer) : TShiftStateEnum;
  163. begin
  164. Case aButton of
  165. MOUSE_PRIMARY: Result:=ssLeft;
  166. MOUSE_SECONDARY : Result:=ssRight;
  167. MOUSE_AUXILIARY : Result:=ssMiddle;
  168. MOUSE_EXTRA1 : Result:=ssExtra1;
  169. MOUSE_EXTRA2 : Result:=ssExtra2;
  170. end;
  171. end;
  172. { ---------------------------------------------------------------------
  173. TCanvasReference
  174. ---------------------------------------------------------------------}
  175. procedure TWasmFresnelApi.ProcessMessages;
  176. var
  177. Callback : JSValue;
  178. begin
  179. if not assigned(InstanceExports) then
  180. Writeln('No instance exports !')
  181. else
  182. begin
  183. Callback:=InstanceExports['__fresnel_process_message'];
  184. if Assigned(Callback) then
  185. begin
  186. TTimerCallback(CallBack)(FLastTick,Now);
  187. FLastTick:=Now;
  188. end
  189. else
  190. Writeln('No processmessages callback !');
  191. end
  192. end;
  193. procedure TWasmFresnelApi.DoTimerTick;
  194. var
  195. Callback : JSValue;
  196. T : TDateTime;
  197. begin
  198. T:=FLastTick;
  199. FLastTick:=Now;
  200. if not assigned(InstanceExports) then
  201. Writeln('No instance exports !')
  202. else
  203. begin
  204. Callback:=InstanceExports['__fresnel_tick'];
  205. if Assigned(Callback) then
  206. begin
  207. TTimerCallback(CallBack)(FLastTick,T);
  208. end
  209. else
  210. Writeln('No tick callback !');
  211. end
  212. end;
  213. constructor TCanvasReference.create(aID: TCanvasID; aAPI: TWasmFresnelApi;
  214. aCanvas: TJSHTMLCanvasElement; aParent: TJSHTMLElement);
  215. begin
  216. Canvas:=aCanvas;
  217. canvasParent:=aParent;
  218. API:=aAPI;
  219. CanvasID:=aID;
  220. PrepareCanvas;
  221. end;
  222. procedure TCanvasReference.PrepareCanvas;
  223. begin
  224. CanvasContext:=TJSCanvasRenderingContext2D(Canvas.getcontext('2d'));
  225. Canvas.AddEventListener('mousedown',@DoMouseDown);
  226. Canvas.AddEventListener('mouseup',@DoMouseUp);
  227. Canvas.AddEventListener('mousemove',@DoMouseMove);
  228. Canvas.AddEventListener('click',@DoMouseClick);
  229. Canvas.AddEventListener('dblclick',@DoMouseDblClick);
  230. Canvas.AddEventListener('scroll',@DoMouseWheel);
  231. end;
  232. procedure TCanvasReference.RemoveCanvas;
  233. begin
  234. CanvasParent.removeChild(Canvas);
  235. Canvas:=Nil;
  236. CanvasParent:=nil;
  237. canvascontext:=nil;
  238. end;
  239. procedure TCanvasReference.SendEvent;
  240. begin
  241. API.ProcessMessages;
  242. end;
  243. function TCanvasReference.MouseToEvent(aEvent : TJSMouseEvent;aMessageID : TCanvasMessageID) : TCanvasEvent;
  244. var
  245. State : TShiftState;
  246. Procedure Check(aButton : Integer);
  247. begin
  248. if (aEvent.buttons and aButton)<>0 then
  249. include(State,TFresnelHelper.MouseButtonToShiftState(aButton));
  250. end;
  251. begin
  252. Result.CanvasID:=Self.CanvasID;
  253. Result.msg:=aMessageID;
  254. Result.param0:=Round(aEvent.OffsetX);
  255. Result.param1:=Round(aEvent.OffsetY);
  256. State:=[];
  257. Check(MOUSE_PRIMARY);
  258. Check(MOUSE_SECONDARY);
  259. Check(MOUSE_AUXILIARY);
  260. Check(MOUSE_EXTRA1);
  261. Check(MOUSE_EXTRA2);
  262. If aEvent.altKey then
  263. Include(State,ssAlt);
  264. If aEvent.ctrlKey then
  265. Include(State,ssCtrl);
  266. If aEvent.shiftKey then
  267. Include(State,ssShift);
  268. if aEvent.metaKey then
  269. Include(State,ssMeta);
  270. Result.Param2:=TFresnelHelper.ShiftStateToInt(State);
  271. end;
  272. function TCanvasReference.DoMouseDown(aEvent: TJSEvent): boolean;
  273. var
  274. Evt : TJSMouseEvent absolute aEvent;
  275. begin
  276. Result:=True;
  277. TJSArray(API.FEvents).Push(MouseToEvent(evt,WASMSG_MOUSEDOWN));
  278. SendEvent;
  279. end;
  280. function TCanvasReference.DoMouseMove(aEvent: TJSEvent): boolean;
  281. var
  282. Evt : TJSMouseEvent absolute aEvent;
  283. begin
  284. Result:=True;
  285. TJSArray(API.FEvents).Push(MouseToEvent(evt,WASMSG_MOVE));
  286. SendEvent;
  287. end;
  288. function TCanvasReference.DoMouseWheel(aEvent: TJSEvent): boolean;
  289. var
  290. JSEvt : TJSWheelEvent absolute aEvent;
  291. CanvasEvt : TCanvasEvent;
  292. begin
  293. Result:=True;
  294. CanvasEvt:=MouseToEvent(JSevt,WASMSG_WHEELY);
  295. Case JSEvt.deltaMode of
  296. 0 : CanvasEvt.Param3:=Round(JSEvt.deltaY);
  297. 1 : CanvasEvt.Param3:=Round(JSEvt.deltaY*12); // arbitrary
  298. 2 : CanvasEvt.Param3:=Round(JSEvt.deltaY*600); // arbitrary
  299. end;
  300. TJSArray(API.FEvents).Push(CanvasEvt);
  301. SendEvent;
  302. end;
  303. function TCanvasReference.DoMouseClick(aEvent: TJSEvent): boolean;
  304. var
  305. Evt : TJSMouseEvent absolute aEvent;
  306. begin
  307. Result:=True;
  308. TJSArray(API.FEvents).Push(MouseToEvent(evt,WASMSG_CLICK));
  309. SendEvent;
  310. end;
  311. function TCanvasReference.DoMouseDblClick(aEvent: TJSEvent): boolean;
  312. var
  313. Evt : TJSMouseEvent absolute aEvent;
  314. begin
  315. Result:=True;
  316. TJSArray(API.FEvents).Push(MouseToEvent(evt,WASMSG_DBLCLICK));
  317. SendEvent;
  318. end;
  319. function TCanvasReference.DoMouseUp(aEvent: TJSEvent): boolean;
  320. var
  321. Evt : TJSMouseEvent absolute aEvent;
  322. begin
  323. Result:=True;
  324. TJSArray(API.FEvents).Push(MouseToEvent(evt,WASMSG_MOUSEUP));
  325. SendEvent;
  326. end;
  327. constructor TWasmFresnelApi.Create(aEnv: TPas2JSWASIEnvironment);
  328. begin
  329. Inherited Create(aEnv);
  330. FCanvases:=TJSObject.New();
  331. FLogAPICalls:=True;
  332. FTimerInterval:=10;
  333. FLastTick:=Now;
  334. end;
  335. function TWasmFresnelApi.ImportName: String;
  336. begin
  337. Result:='fresnel_api';
  338. end;
  339. function TWasmFresnelApi.GetCanvasRef(aID : TCanvasID) : TCanvasReference;
  340. var
  341. JS : JSValue;
  342. begin
  343. JS:=FCanvases[IntTostr(AID)];
  344. if IsObject(JS) then
  345. Result:= TCanvasReference(JS)
  346. else
  347. Result:=nil;
  348. end;
  349. class function TFresnelHelper.AllocateCanvasID: TCanvasID;
  350. begin
  351. Inc(_CurrentID);
  352. Result:=_CurrentID;
  353. end;
  354. procedure TWasmFresnelApi.LogCall(const Msg: String);
  355. begin
  356. {$IFNDEF NOLOGAPICALLS}
  357. If not LogAPICalls then exit;
  358. Writeln(Msg);
  359. {$ENDIF}
  360. end;
  361. procedure TWasmFresnelApi.LogCall(const Fmt: String; const Args: array of const);
  362. begin
  363. {$IFNDEF NOLOGAPICALLS}
  364. If not LogAPICalls then exit;
  365. Writeln(Format(Fmt,Args));
  366. {$ENDIF}
  367. end;
  368. function TWasmFresnelApi.GetCanvas(aID : TCanvasID) : TJSCanvasRenderingContext2D;
  369. Var
  370. Ref : TCanvasReference;
  371. begin
  372. Ref:=GetCanvasRef(aID);
  373. if Assigned(Ref) then
  374. Result:= Ref.canvascontext
  375. else
  376. begin
  377. Writeln('Unknown canvas : ',aID);
  378. Result:=Nil;
  379. end;
  380. end;
  381. procedure TWasmFresnelApi.FillImportObject(aObject: TJSObject);
  382. begin
  383. // Canvas
  384. aObject['canvas_allocate']:=@AllocateCanvas;
  385. aObject['canvas_getbyid']:=@getcanvasbyid;
  386. aObject['canvas_getsizes']:=@getcanvassizes;
  387. aObject['canvas_moveto']:=@moveto;
  388. aObject['canvas_lineto']:=@LineTo;
  389. aObject['canvas_stroke']:=@stroke;
  390. aObject['canvas_beginpath']:=@beginpath;
  391. aObject['canvas_arc']:=@arc;
  392. aObject['canvas_fillrect']:=@fillrect;
  393. aObject['canvas_strokerect']:=@strokerect;
  394. aObject['canvas_clearrect']:=@clearrect;
  395. aObject['canvas_stroketext']:=@StrokeText;
  396. aObject['canvas_filltext']:=@FillText;
  397. aObject['canvas_set_fillstyle']:=@SetFillStyle;
  398. aObject['canvas_linear_gradient_fillstyle']:=@SetLinearGradientFillStyle;
  399. aObject['canvas_image_fillstyle']:=@SetImageFillStyle;
  400. aObject['canvas_set_strokestyle']:=@SetStrokeStyle;
  401. aObject['canvas_set_linewidth']:=@SetLineWidth;
  402. aObject['canvas_set_linecap']:=@SetLineCap;
  403. aObject['canvas_set_linejoin']:=@SetLineJoin;
  404. aObject['canvas_set_linemiterlimit']:=@SetLineMiterLimit;
  405. aObject['canvas_set_linedash']:=@SetLineDash;
  406. aObject['canvas_draw_image']:=@DrawImage;
  407. aObject['canvas_set_font']:=@SetFont;
  408. aObject['canvas_measure_text']:=@MeasureText;
  409. aObject['canvas_set_textshadow_params']:=@SetTextShadowParams;
  410. aObject['canvas_roundrect']:=@RoundRect;
  411. aObject['canvas_draw_path']:=@DrawPath;
  412. aObject['canvas_point_in_path']:=@PointInPath;
  413. aObject['canvas_set_transform']:=@SetTransForm;
  414. aObject['canvas_clear']:=@ClearCanvas;
  415. // Timer
  416. aObject['timer_allocate']:=@AllocateTimer;
  417. aObject['timer_deallocate']:=@DeAllocateTimer;
  418. // Event
  419. aObject['event_get']:=@GetEvent;
  420. aObject['event_count']:=@GetEventCount;
  421. end;
  422. procedure TWasmFresnelApi.StartTimerTick;
  423. begin
  424. FTimerID:=Window.setInterval(@DoTimerTick,FTimerInterval);
  425. end;
  426. procedure TWasmFresnelApi.StopTimerTick;
  427. begin
  428. Window.clearInterval(FTimerID);
  429. end;
  430. function TWasmFresnelApi.GetCanvasSizes(aID: TCanvasID; aWidth, aHeight: TWasmPointer): TCanvasError;
  431. var
  432. Ref: TCanvasReference;
  433. v : TJSDataView;
  434. begin
  435. {$IFNDEF NOLOGAPICALLS}
  436. If LogAPICalls then
  437. begin
  438. LogCall('Canvas.GetCanvasSizes(%d,[%x],[%x])',[aID,aWidth,aHeight]);
  439. end;
  440. {$ENDIF}
  441. Ref:=GetCanvasRef(aID);
  442. if Not Assigned(Ref) then
  443. Exit(ECANVAS_NOCANVAS);
  444. v:=getModuleMemoryDataView;
  445. v.setint32(aWidth,Ref.canvas.width,env.IsLittleEndian);
  446. v.setint32(aHeight,Ref.canvas.height,env.IsLittleEndian);
  447. Result:=ECANVAS_SUCCESS;
  448. end;
  449. function TWasmFresnelApi.SetFillStyle(aID: TCanvasID; aRed, aGreen, aBlue, aAlpha: TCanvasColorComponent): TCanvasError;
  450. var
  451. Canv : TJSCanvasRenderingContext2D;
  452. S : String;
  453. begin
  454. {$IFNDEF NOLOGAPICALLS}
  455. If LogAPICalls then
  456. begin
  457. LogCall('Canvas.SetFillStyle(%d,%d,%d,%d,%d)',[aID,aRed,aGreen,aBlue,aAlpha]);
  458. end;
  459. {$ENDIF}
  460. Canv:=GetCanvas(aID);
  461. if Not Assigned(Canv) then
  462. Exit(ECANVAS_NOCANVAS);
  463. S:=TFresnelHelper.FresnelColorToHTMLColor(aRed,aGreen,aBlue,aAlpha);
  464. // Writeln('Fill: ',S);
  465. Canv.fillStyle:=S;
  466. Exit(ECANVAS_SUCCESS);
  467. end;
  468. function TWasmFresnelApi.ClearCanvas(aID: TCanvasID; aRed, aGreen, aBlue,
  469. aAlpha: TCanvasColorComponent): TCanvasError;
  470. var
  471. Ref : TCanvasReference;
  472. S : String;
  473. begin
  474. {$IFNDEF NOLOGAPICALLS}
  475. If LogAPICalls then
  476. begin
  477. LogCall('Canvas.SetFillStyle(%d,%d,%d,%d,%d)',[aID,aRed,aGreen,aBlue,aAlpha]);
  478. end;
  479. {$ENDIF}
  480. Ref:=GetCanvasRef(aID);
  481. if Not Assigned(ref) then
  482. Exit(ECANVAS_NOCANVAS);
  483. S:=TFresnelHelper.FresnelColorToHTMLColor(aRed,aGreen,aBlue,aAlpha);
  484. // Writeln('Fill: ',S);
  485. Ref.canvascontext.fillStyle:=S;
  486. Ref.canvascontext.FillRect(0,0,Ref.canvas.width,Ref.canvas.height);
  487. Exit(ECANVAS_SUCCESS);
  488. end;
  489. function TWasmFresnelApi.SetLinearGradientFillStyle(aID: TCanvasID; aStartX, aStartY, aEndX, aEndY: Longint;
  490. aColorPointCount: longint; aColorPoints: TWasmPointer): TCanvasError;
  491. var
  492. I,P : Longint;
  493. Red,Green,Blue,Alpha: Longint;
  494. offset : double;
  495. G : TJSCanvasGradient;
  496. Canv : TJSCanvasRenderingContext2D;
  497. V : TJSDataView;
  498. S : String;
  499. function GetLongint: longint;
  500. begin
  501. Result:=V.getInt32(P,Env.IsLittleEndian);
  502. Inc(P,4);
  503. end;
  504. begin
  505. {$IFNDEF NOLOGAPICALLS}
  506. If LogAPICalls then
  507. begin
  508. LogCall('Canvas.SetLinearGradientFillStyle(%d,(%d,%d),(%d,%d),%d,[%x])',[aID,aStartX, aStartY, aEndX, aEndY, aColorPointCount,aColorPoints]);
  509. end;
  510. {$ENDIF}
  511. Canv:=GetCanvas(aID);
  512. if Not Assigned(Canv) then
  513. Exit(ECANVAS_NOCANVAS);
  514. G:=Canv.createLinearGradient(aStartX,aStartY,aEndX,aEndY);
  515. V:=getModuleMemoryDataView;
  516. P:=aColorPoints;
  517. For I:=0 to aColorPointCount-1 do
  518. begin
  519. Red:=GetLongint;
  520. Green:=GetLongint;
  521. Blue:=GetLongint;
  522. Alpha:=GetLongint;
  523. offset:=GetLongint/10000;
  524. S:=TFresnelHelper.FresnelColorToHTMLColor(Red,Green,Blue,Alpha);
  525. G.addColorStop(offset,S);
  526. end;
  527. Canv.fillStyleAsGradient:=G;
  528. Exit(ECANVAS_SUCCESS);
  529. end;
  530. function TWasmFresnelApi.SetImageFillStyle(aID: TCanvasID; Flags: Longint;
  531. aImageWidth, aImageHeight: Longint; aImageData: TWasmPointer): TCanvasError;
  532. var
  533. OSC : TJSHTMLOffscreenCanvasElement;
  534. ImgData : TJSImageData;
  535. // OSCImgBitmap : TJSImageBitmap;
  536. Canv,Canv2 : TJSCanvasRenderingContext2D;
  537. D : TJSUint8ClampedArray;
  538. V : TJSDataView;
  539. S : String;
  540. begin
  541. {$IFNDEF NOLOGAPICALLS}
  542. If LogAPICalls then
  543. begin
  544. LogCall('Canvas.SetImageFillStyle(%d,%d,(%d,%d),[%x])',[aID,flags,aImageWidth,aImageHeight,aImageData]);
  545. end;
  546. {$ENDIF}
  547. Canv:=GetCanvas(aID);
  548. if Not Assigned(Canv) then
  549. Exit(ECANVAS_NOCANVAS);
  550. V:=getModuleMemoryDataView;
  551. D:=TJSUint8ClampedArray.New(V.Buffer,aImageData,aImageWidth*aImageWidth*4);
  552. ImgData:=TJSImageData.new(D,aImageWidth,aImageWidth);
  553. OSC:=TJSHTMLOffscreenCanvasElement.New(aImageWidth,aImageHeight);
  554. Canv2:=OSC.getContextAs2DContext('2d');
  555. Canv2.clearRect(0,0,aImageWidth,aImageHeight);
  556. Canv2.putImageData(ImgData,0,0);
  557. Case flags and 3 of
  558. IMAGEFILLSTYLE_NOREPEAT : s:='no-repeat';
  559. IMAGEFILLSTYLE_REPEAT : s:='repeat';
  560. IMAGEFILLSTYLE_REPEATX : s:='repeat-x';
  561. IMAGEFILLSTYLE_REPEATY : s:='repeat-y';
  562. end;
  563. Canv.fillStyleAsPattern:=Canv.createPattern(OSC,S);
  564. end;
  565. function TWasmFresnelApi.SetStrokeStyle(aID: TCanvasID; aRed, aGreen, aBlue, aAlpha: TCanvasColorComponent): TCanvasError;
  566. var
  567. Canv : TJSCanvasRenderingContext2D;
  568. S : String;
  569. begin
  570. {$IFNDEF NOLOGAPICALLS}
  571. If LogAPICalls then
  572. begin
  573. LogCall('Canvas.SetStrokeStyle(%d,%d,%d,%d,%d)',[aID,aRed,aGreen,aBlue,aAlpha]);
  574. end;
  575. {$ENDIF}
  576. Canv:=GetCanvas(aID);
  577. if Not Assigned(Canv) then
  578. Exit(ECANVAS_NOCANVAS);
  579. S:=TFresnelHelper.FresnelColorToHTMLColor(aRed,aGreen,aBlue,aAlpha);
  580. Canv.StrokeStyle:=S;
  581. Result:=ECANVAS_SUCCESS;
  582. end;
  583. function TWasmFresnelApi.DrawImage(aID: TCanvasID; aX, aY, aWidth, aHeight, aImageWidth, aImageHeight: Longint;
  584. aImageData: TWasmPointer): TCanvasError;
  585. var
  586. V : TJSDataView;
  587. D : TJSUint8ClampedArray;
  588. ImgData : TJSImageData;
  589. Canv : TJSCanvasRenderingContext2D;
  590. {$IFDEF IMAGE_USEOSC}
  591. Canv2 : TJSCanvasRenderingContext2D;
  592. OSC : TJSHTMLOffscreenCanvasElement;
  593. {$ENDIF}
  594. begin
  595. {$IFNDEF NOLOGAPICALLS}
  596. If LogAPICalls then
  597. begin
  598. LogCall('Canvas.DrawImage(%d,%d,%d,%d,%d,%d,%d)',[aID,aX,aY,aWidth,aHeight,aImageWidth,aImageHeight]);
  599. end;
  600. {$ENDIF}
  601. Canv:=GetCanvas(aID);
  602. if Not Assigned(Canv) then
  603. Exit(ECANVAS_NOCANVAS);
  604. V:=getModuleMemoryDataView;
  605. D:=TJSUint8ClampedArray.New(V.Buffer,aImageData,aImageWidth*aImageWidth*4);
  606. ImgData:=TJSImageData.new(D,aImageWidth,aImageWidth);
  607. {$IFDEF IMAGE_USEOSC}
  608. OSC:=TJSHTMLOffscreenCanvasElement.New(aImageWidth,aImageHeight);
  609. Canv2:=OSC.getContextAs2DContext('2d');
  610. Canv2.clearRect(0,0,aImageWidth,aImageHeight);
  611. Canv2.putImageData(ImgData,0,0);
  612. Canv.drawImage(OSC,aX,aY,aWidth,aHeight);
  613. {$ELSE}
  614. Window.createImageBitmap(ImgData)._then(
  615. function (res : jsvalue) : JSValue
  616. var
  617. ImgBitmap : TJSImageBitmap absolute res;
  618. begin
  619. Canv.drawImage(ImgBitmap,aX,aY,aWidth,aHeight);
  620. end);
  621. {$ENDIF}
  622. Result:=ECANVAS_SUCCESS;
  623. end;
  624. function TWasmFresnelApi.SetFont(aID: TCanvasID; aFontName: TWasmPointer; aFontNameLen: integer): TCanvasError;
  625. var
  626. S : String;
  627. Canv:TJSCanvasRenderingContext2D;
  628. begin
  629. S:=Env.GetUTF8StringFromMem(aFontName,aFontNameLen);
  630. {$IFNDEF NOLOGAPICALLS}
  631. If LogAPICalls then
  632. begin
  633. LogCall('Canvas.SetFont(%d,"%s")',[aID,S]);
  634. end;
  635. {$ENDIF}
  636. Canv:=GetCanvas(aID);
  637. if Not Assigned(Canv) then
  638. Exit(ECANVAS_NOCANVAS);
  639. Canv.font:=S;
  640. Result:=ECANVAS_SUCCESS;
  641. end;
  642. function TWasmFresnelApi.MeasureText(aID: TCanvasID; aText: TWasmPointer; aTextLen: integer; aWidth, aHeight: Longint
  643. ): TCanvasError;
  644. var
  645. S : String;
  646. Canv:TJSCanvasRenderingContext2D;
  647. M : TJSTextMetrics;
  648. V : TJSDataView;
  649. W,H : Double;
  650. begin
  651. S:=Env.GetUTF8StringFromMem(aText,aTextLen);
  652. {$IFNDEF NOLOGAPICALLS}
  653. If LogAPICalls then
  654. begin
  655. LogCall('Canvas.MeasureText(%d,"%s")',[aID,S]);
  656. end;
  657. {$ENDIF}
  658. Canv:=GetCanvas(aID);
  659. if Not Assigned(Canv) then
  660. Exit(ECANVAS_NOCANVAS);
  661. M:=Canv.measureText(S);
  662. W:=M.width;
  663. H:=M.actualBoundingBoxAscent +M.actualBoundingBoxDescent;
  664. V:=getModuleMemoryDataView;
  665. {$IFNDEF NOLOGAPICALLS}
  666. If LogAPICalls then
  667. begin
  668. LogCall('Canvas.MeasureText(%d,"%s") : [%g,%g]',[aID,S,W,H]);
  669. end;
  670. {$ENDIF}
  671. v.setint32(aWidth,Round(W),env.IsLittleEndian);
  672. v.setint32(aHeight,Round(H),env.IsLittleEndian);
  673. Result:=ECANVAS_SUCCESS;
  674. end;
  675. function TWasmFresnelApi.SetTextShadowParams (aID : TCanvasID; aOffsetX,aOffsetY,aRadius : Longint; aRed,aGreen,aBlue,aAlpha : TCanvasColorComponent): TCanvasError;
  676. var
  677. Canv:TJSCanvasRenderingContext2D;
  678. begin
  679. {$IFNDEF NOLOGAPICALLS}
  680. If LogAPICalls then
  681. begin
  682. LogCall('Canvas.SetTextShadowParams(%d,%d,%d,%d,"%s")',[aID,aOffsetX,aOffsetY,aRadius,TFresnelHelper.FresnelColorToHTMLColor(aRed,aGreen,aBlue,aAlpha)]);
  683. end;
  684. {$ENDIF}
  685. Canv:=GetCanvas(aID);
  686. if Not Assigned(Canv) then
  687. Exit(ECANVAS_NOCANVAS);
  688. Canv.shadowOffsetX:=aOffsetX;
  689. Canv.shadowOffsetY:=aOffsetY;
  690. Canv.shadowBlur:=FresnelUnScale(aRadius);
  691. Canv.shadowColor:=TFresnelHelper.FresnelColorToHTMLColor(aRed,aGreen,aBlue,aAlpha);
  692. Result:=ECANVAS_SUCCESS;
  693. end;
  694. function TWasmFresnelApi.DrawPath(aID: TCanvasID; aFlags: Longint;
  695. aPathCount: longint; aPath: TWasmPointer): TCanvasError;
  696. var
  697. Canv:TJSCanvasRenderingContext2D;
  698. P2D : TJSPath2D;
  699. aType,X,Y,X1,Y1,X2,Y2,X3,Y3,I : Integer;
  700. V : TJSDataView;
  701. P : TWasmPointer;
  702. WasClosed : Boolean;
  703. Procedure GetTriple;
  704. begin
  705. aType:=V.getInt32(P,env.IsLittleEndian);
  706. Inc(P);
  707. X:=V.getInt32(P,env.IsLittleEndian);
  708. inc(P);
  709. Y:=V.getInt32(P,env.IsLittleEndian);
  710. inc(P);
  711. end;
  712. begin
  713. {$IFNDEF NOLOGAPICALLS}
  714. If LogAPICalls then
  715. begin
  716. LogCall('Canvas.DrawPath(%d,%d,%d,[%x])',[aID,aFlags,aPathCount,aPath]);
  717. end;
  718. {$ENDIF}
  719. WasClosed:=False;
  720. Canv:=GetCanvas(aID);
  721. if Not Assigned(Canv) then
  722. Exit(ECANVAS_NOCANVAS);
  723. if aPathCount=0 then
  724. Exit(ECANVAS_INVALIDPATH);
  725. V:=getModuleMemoryDataView;
  726. P:=aPath;
  727. P2D:=TJSPath2D.New;
  728. For I:=1 to aPathCount-1 do
  729. begin
  730. GetTriple;
  731. WasClosed:=aType<>DRAWPATH_TYPECLOSE;
  732. Case aType of
  733. DRAWPATH_TYPEMOVETO : P2D.MoveTo(X,Y);
  734. DRAWPATH_TYPELINETO : P2D.LineTo(X,Y);
  735. DRAWPATH_TYPECURVETO :
  736. begin
  737. X1:=X;
  738. Y1:=Y;
  739. GetTriple;
  740. if aType<>DRAWPATH_TYPECURVETO then
  741. begin
  742. Writeln('Invalid path data 2, expected CURVETO (',DRAWPATH_TYPECURVETO,'), got: ',aType);
  743. exit;
  744. end;
  745. X2:=X;
  746. Y2:=Y;
  747. GetTriple;
  748. if aType<>DRAWPATH_TYPECURVETO then
  749. begin
  750. Writeln('Invalid path data 3, expected CURVETO (',DRAWPATH_TYPECURVETO,'), got: ',aType);
  751. exit;
  752. end;
  753. X3:=X;
  754. Y3:=Y;
  755. P2D.bezierCurveTo(X1,Y1,X2,Y2,X3,Y3);
  756. end;
  757. DRAWPATH_TYPECLOSE :
  758. P2D.ClosePath;
  759. end;
  760. end;
  761. if not WasClosed and ((aFlags and DRAWPATH_CLOSEPATH)<>0) then
  762. P2D.closePath;
  763. if (aFlags and DRAWPATH_FILLPATH)<>0 then
  764. Canv.Fill(P2D);
  765. if (aFlags and DRAWPATH_STROKEPATH)<>0 then
  766. Canv.Stroke(P2D);
  767. Result:=ECANVAS_SUCCESS;
  768. end;
  769. function TWasmFresnelApi.PointInPath(aID: TCanvasID; aX: Longint; aY: Longint;
  770. aPointCount: Integer; aPointData: TWasmPointer; aRes: TWasmPointer): TCanvasError;
  771. var
  772. Canv:TJSCanvasRenderingContext2D;
  773. P2D : TJSPath2D;
  774. aType,X,Y,X1,Y1,X2,Y2,X3,Y3,I : Integer;
  775. V : TJSDataView;
  776. P : TWasmPointer;
  777. WasClosed : Boolean;
  778. Res : Boolean;
  779. Procedure GetTriple;
  780. begin
  781. aType:=V.getInt32(P,env.IsLittleEndian);
  782. Inc(P);
  783. X:=V.getInt32(P,env.IsLittleEndian);
  784. inc(P);
  785. Y:=V.getInt32(P,env.IsLittleEndian);
  786. inc(P);
  787. end;
  788. begin
  789. {$IFNDEF NOLOGAPICALLS}
  790. If LogAPICalls then
  791. begin
  792. LogCall('Canvas.PointInPath(%d,(%d,%d),%d,[%x],[%x])',[aID,aX,aY,aPointCount,aPointData,aRes]);
  793. end;
  794. {$ENDIF}
  795. WasClosed:=False;
  796. Canv:=GetCanvas(aID);
  797. if Not Assigned(Canv) then
  798. Exit(ECANVAS_NOCANVAS);
  799. if aPointCount=0 then
  800. Exit(ECANVAS_INVALIDPATH);
  801. V:=getModuleMemoryDataView;
  802. P:=aPointData;
  803. P2D:=TJSPath2D.New;
  804. For I:=1 to aPointCount-1 do
  805. begin
  806. GetTriple;
  807. WasClosed:=aType<>DRAWPATH_TYPECLOSE;
  808. Case aType of
  809. DRAWPATH_TYPEMOVETO : P2D.MoveTo(X,Y);
  810. DRAWPATH_TYPELINETO : P2D.LineTo(X,Y);
  811. DRAWPATH_TYPECURVETO :
  812. begin
  813. X1:=X;
  814. Y1:=Y;
  815. GetTriple;
  816. if aType<>DRAWPATH_TYPECURVETO then
  817. begin
  818. Writeln('Invalid path data 2, expected CURVETO (',DRAWPATH_TYPECURVETO,'), got: ',aType);
  819. exit(ECANVAS_INVALIDPATH);
  820. end;
  821. X2:=X;
  822. Y2:=Y;
  823. GetTriple;
  824. if aType<>DRAWPATH_TYPECURVETO then
  825. begin
  826. Writeln('Invalid path data 3, expected CURVETO (',DRAWPATH_TYPECURVETO,'), got: ',aType);
  827. exit(ECANVAS_INVALIDPATH);
  828. end;
  829. X3:=X;
  830. Y3:=Y;
  831. P2D.bezierCurveTo(X1,Y1,X2,Y2,X3,Y3);
  832. end;
  833. DRAWPATH_TYPECLOSE :
  834. P2D.ClosePath;
  835. end;
  836. end;
  837. if not WasClosed then
  838. P2D.closePath;
  839. Res:=Canv.isPointInPath(P2D,aX,aY);
  840. v.setInt8(aRes,Ord(Res));
  841. Result:=ECANVAS_SUCCESS;
  842. end;
  843. function TWasmFresnelApi.SetTransform(aID: TCanvasID; Flags: Longint; m11, m12,
  844. m21, m22, m31, m32: Longint): TCanvasError;
  845. var
  846. Canv:TJSCanvasRenderingContext2D;
  847. begin
  848. {$IFNDEF NOLOGAPICALLS}
  849. If LogAPICalls then
  850. begin
  851. LogCall('Canvas.SetTransform(%d,%d,%d,%d,%d,%d,%d,%d)',[aID,Flags,m11,m12,m21,m22,m31,m32]);
  852. end;
  853. {$ENDIF}
  854. Canv:=GetCanvas(aID);
  855. if Not Assigned(Canv) then
  856. Exit(ECANVAS_NOCANVAS);
  857. if (Flags and TRANSFORM_RESET)<>0 then
  858. canv.setTransform(FresnelUnScale(m11),FresnelUnScale(m12),FresnelUnScale(m21),FresnelUnScale(m22),FresnelUnScale(m31),FresnelUnScale(m32))
  859. else
  860. canv.transform(FresnelUnScale(m11),FresnelUnScale(m12),FresnelUnScale(m21),FresnelUnScale(m22),FresnelUnScale(m31),FresnelUnScale(m32));
  861. end;
  862. function TWasmFresnelApi.AllocateTimer(ainterval: longint; userdata: TWasmPointer): TTimerID;
  863. var
  864. aTimerID : TTimerID;
  865. CallBack:jsvalue;
  866. Procedure HandleTimer;
  867. var
  868. Continue : boolean;
  869. begin
  870. // The instance/timer could have disappeared
  871. Callback:=InstanceExports['__fresnel_timer_tick'];
  872. Continue:=Assigned(Callback);
  873. if Continue then
  874. Continue:=TTimerTickCallback(CallBack)(aTimerID,userData)
  875. else
  876. Writeln('No more tick callback !');
  877. if not Continue then
  878. DeAllocateTimer(aTimerID);
  879. end;
  880. begin
  881. Callback:=InstanceExports['__fresnel_timer_tick'];
  882. if Not Assigned(Callback) then
  883. Exit(0);
  884. aTimerID:=Window.setInterval(@HandleTimer,aInterval);
  885. Result:=aTimerID;
  886. end;
  887. procedure TWasmFresnelApi.DeallocateTimer(timerid: TTimerID);
  888. begin
  889. window.clearTimeout(TimerID);
  890. end;
  891. function TWasmFresnelApi.SetLineWidth(aID : TCanvasID;aWidth : TCanvasLineWidth): TCanvasError;
  892. var
  893. Canv:TJSCanvasRenderingContext2D;
  894. begin
  895. {$IFNDEF NOLOGAPICALLS}
  896. If LogAPICalls then
  897. begin
  898. LogCall('Canvas.SetLineWidth(%d,%g)',[aID,FresnelUnscale(aWidth)]);
  899. end;
  900. {$ENDIF}
  901. Canv:=GetCanvas(aID);
  902. if Not Assigned(Canv) then
  903. Exit(ECANVAS_NOCANVAS);
  904. Canv.LineWidth:=FresnelUnScale(aWidth);
  905. Result:=ECANVAS_SUCCESS;
  906. end;
  907. function TWasmFresnelApi.SetLineCap(aID : TCanvasID; aCap : TCanvasLinecap): TCanvasError;
  908. var
  909. Canv:TJSCanvasRenderingContext2D;
  910. S : String;
  911. begin
  912. S:=LineCapToString(aCap);
  913. {$IFNDEF NOLOGAPICALLS}
  914. If LogAPICalls then
  915. begin
  916. LogCall('Canvas.SetLineCap(%d,%s)',[aID,S]);
  917. end;
  918. {$ENDIF}
  919. Canv:=GetCanvas(aID);
  920. if Not Assigned(Canv) then
  921. Exit(ECANVAS_NOCANVAS);
  922. Canv.lineCap:=S;
  923. Result:=ECANVAS_SUCCESS;
  924. end;
  925. function TWasmFresnelApi.SetLineJoin(aID : TCanvasID; aJoin : TCanvasLineJoin): TCanvasError;
  926. var
  927. Canv:TJSCanvasRenderingContext2D;
  928. S : String;
  929. begin
  930. S:=LineJoinToString(aJoin);
  931. {$IFNDEF NOLOGAPICALLS}
  932. If LogAPICalls then
  933. begin
  934. LogCall('Canvas.SetLineJoin(%d,%s)',[aID,S]);
  935. end;
  936. {$ENDIF}
  937. Canv:=GetCanvas(aID);
  938. if Not Assigned(Canv) then
  939. Exit(ECANVAS_NOCANVAS);
  940. Canv.lineJoin:=S;
  941. Result:=ECANVAS_SUCCESS;
  942. end;
  943. function TWasmFresnelApi.SetLineMiterLimit(aID : TCanvasID; aWidth : TCanvasLineMiterLimit): TCanvasError;
  944. var
  945. Canv:TJSCanvasRenderingContext2D;
  946. begin
  947. {$IFNDEF NOLOGAPICALLS}
  948. If LogAPICalls then
  949. begin
  950. LogCall('Canvas.SetLineMiterLimit(%d,%d)',[aID,aWidth]);
  951. end;
  952. {$ENDIF}
  953. Canv:=GetCanvas(aID);
  954. if Not Assigned(Canv) then
  955. Exit(ECANVAS_NOCANVAS);
  956. Canv.miterLimit:=FresnelUnscale(aWidth);
  957. Result:=ECANVAS_SUCCESS;
  958. LogCall('Canvas.SetLineMiterLimit not implemented');
  959. end;
  960. function TWasmFresnelApi.SetLineDash(aID: TCanvasID; aOffset: Longint;
  961. aPatternCount: longint; aPattern: TWasmPointer): TCanvasError;
  962. var
  963. Dashes : TJSArray;
  964. V : TJSDataView;
  965. I : Integer;
  966. P : TWasmPointer;
  967. Canv:TJSCanvasRenderingContext2D;
  968. begin
  969. {$IFNDEF NOLOGAPICALLS}
  970. If LogAPICalls then
  971. begin
  972. LogCall('Canvas.SetLineDash(%d,%g,%d,[%x])',[aID,FresnelUnscale(aOffset),aPatternCount,aPattern]);
  973. end;
  974. {$ENDIF}
  975. Canv:=GetCanvas(aID);
  976. if Not Assigned(Canv) then
  977. Exit(ECANVAS_NOCANVAS);
  978. Dashes:=TJSArray.New;
  979. if aPatternCount>0 then
  980. begin
  981. V:=getModuleMemoryDataView;
  982. P:=aPattern;
  983. for I:=0 to APatternCount-1 do
  984. begin
  985. Dashes.Push(FresnelUnScale(v.Getint32(P,env.IsLittleEndian)));
  986. Inc(P,4);
  987. end;
  988. end;
  989. Canv.lineDashOffset:=FresnelUnscale(aOffset);
  990. Canv.setLineDash(Dashes);
  991. end;
  992. { ---------------------------------------------------------------------
  993. Event API
  994. ---------------------------------------------------------------------}
  995. // note that the events are for a single canvas !
  996. function TWasmFresnelApi.GetEvent(aID: TWasmPointer; aMsg: TWasmPointer; Data: TWasmPointer): TCanvasError;
  997. const
  998. Int32Size = 4;
  999. var
  1000. V : TJSDataView;
  1001. Evt : TCanvasEvent;
  1002. begin
  1003. if Length(FEvents)=0 then
  1004. Exit(EWASMEVENT_NOEVENT);
  1005. Evt:=FEvents[0];
  1006. Delete(FEvents,0,1);
  1007. V:=getModuleMemoryDataView;
  1008. v.setint32(aID,Evt.CanvasID,env.IsLittleEndian);
  1009. v.setint32(aMsg,Evt.Msg,env.IsLittleEndian);
  1010. v.setint32(Data,Evt.param0,env.IsLittleEndian);
  1011. inc(Data,Int32Size);
  1012. v.setint32(Data,Evt.param1,env.IsLittleEndian);
  1013. inc(Data,Int32Size);
  1014. v.setint32(Data,Evt.param2,env.IsLittleEndian);
  1015. inc(Data,Int32Size);
  1016. v.setint32(Data,Evt.param3,env.IsLittleEndian);
  1017. Result:=EWASMEVENT_SUCCESS;
  1018. end;
  1019. function TWasmFresnelApi.GetEventCount(aCount: TWasmPointer): TCanvasError;
  1020. var
  1021. V : TJSDataView;
  1022. begin
  1023. V:=getModuleMemoryDataView;
  1024. v.setint32(aCount,Length(FEvents),env.IsLittleEndian);
  1025. Result:=EWASMEVENT_SUCCESS;
  1026. end;
  1027. function TWasmFresnelApi.getcanvasbyid(aCanvasElementID: TWasmPointer; aElementIDLen: Longint; aID: TWasmPointer): TCanvasError;
  1028. var
  1029. S : String;
  1030. El : TJSElement;
  1031. V : TJSDataView;
  1032. aCanvasID : TCanvasID;
  1033. begin
  1034. S:=Env.GetUTF8StringFromMem(aCanvasElementID,aElementIDLen);
  1035. {$IFNDEF NOLOGAPICALLS}
  1036. If LogAPICalls then
  1037. begin
  1038. LogCall('Canvas.GetCanvasByID(''%s'')',[S]);
  1039. end;
  1040. {$ENDIF}
  1041. el:=Nil;
  1042. if (S<>'') then
  1043. El:=Window.Document.getElementById(S);
  1044. if (El=Nil) then
  1045. Exit(ECANVAS_NOCANVAS);
  1046. if not Sametext(el.tagName,'CANVAS') then
  1047. Exit(ECANVAS_NOCANVAS);
  1048. V:=getModuleMemoryDataView;
  1049. aCanvasID:=TFresnelHelper.AllocateCanvasID;
  1050. FCanvases[IntToStr(aCanvasID)]:=TCanvasReference.Create(aID,Self,TJSHTMLCanvasElement(el),TJSHTMLElement(el.parentElement));
  1051. v.setUint32(aID, aCanvasID, env.IsLittleEndian);
  1052. Result:=ECANVAS_SUCCESS;
  1053. end;
  1054. function TWasmFresnelApi.deallocatecanvas(aID: TCanvasID): TCanvasError;
  1055. var
  1056. Ref : TCanvasReference;
  1057. begin
  1058. Ref:=GetCanvasRef(aID);
  1059. if not assigned(Ref) then
  1060. Exit(ECANVAS_NOCANVAS);
  1061. Ref.RemoveCanvas;
  1062. FCanvases[IntToStr(aID)]:=Undefined;
  1063. Ref.Free;
  1064. Result:=ECANVAS_SUCCESS;
  1065. end;
  1066. function TWasmFresnelApi.allocatecanvas(SizeX: Longint; SizeY: Longint;
  1067. aID: TWasmPointer): TCanvasError;
  1068. Var
  1069. CParent : TJSHTMLElement;
  1070. Canv : TJSHTMLCanvasElement;
  1071. Ref : TCanvasReference;
  1072. V : TJSDataView;
  1073. aCanvasID : TCanvasID;
  1074. SID: String;
  1075. begin
  1076. {$IFNDEF NOLOGAPICALLS}
  1077. If LogAPICalls then
  1078. LogCall('Canvas.AllocateCanvas(%d,%d)',[SizeX,SizeY]);
  1079. {$ENDIF}
  1080. aCanvasID:=TFresnelHelper.AllocateCanvasID;
  1081. sID:=IntToStr(aCanvasID);
  1082. CParent:=TJSHTMLElement(document.createElement('div'));
  1083. CParent.id:='ffp'+sID;
  1084. CanvasParent.AppendChild(CParent);
  1085. Canv:=TJSHTMLCanvasElement(document.createElement('CANVAS'));
  1086. Canv.id:='ffc'+sID;
  1087. Canv.width:=SizeX;
  1088. Canv.height:=SizeY;
  1089. CParent.AppendChild(Canv);
  1090. V:=getModuleMemoryDataView;
  1091. Ref:=TCanvasReference.Create(aCanvasID,Self,Canv,CParent);
  1092. Ref.canvascontext.textBaseline:='top';
  1093. FCanvases[sID]:=Ref;
  1094. v.setUint32(aID, aCanvasID, env.IsLittleEndian);
  1095. Result:=ECANVAS_SUCCESS;
  1096. end;
  1097. function TWasmFresnelApi.moveto(aID : TCanvasID; X : Longint;Y : Longint): TCanvasError;
  1098. Var
  1099. C : TJSCanvasRenderingContext2D;
  1100. begin
  1101. {$IFNDEF NOLOGAPICALLS}
  1102. If LogAPICalls then
  1103. LogCall('Canvas.MoveTo(%d,%d,%d)',[aID,X,Y]);
  1104. {$ENDIF}
  1105. Result:=ECANVAS_NOCANVAS;
  1106. C:=GetCanvas(aID);
  1107. if Assigned(C) then
  1108. begin
  1109. C.moveto(X,Y);
  1110. Result:=ECANVAS_SUCCESS;
  1111. end;
  1112. end;
  1113. function TWasmFresnelApi.lineto(aID : TCanvasID;X : Longint; Y : Longint ): TCanvasError;
  1114. Var
  1115. C : TJSCanvasRenderingContext2D;
  1116. begin
  1117. {$IFNDEF NOLOGAPICALLS}
  1118. If LogAPICalls then
  1119. LogCall('Canvas.LineTo(%d,%d,%d)',[aID,X,Y]);
  1120. {$ENDIF}
  1121. Result:=ECANVAS_NOCANVAS;
  1122. C:=GetCanvas(aID);
  1123. if Assigned(C) then
  1124. begin
  1125. C.lineto(X,Y);
  1126. Result:=ECANVAS_SUCCESS;
  1127. end;
  1128. end;
  1129. function TWasmFresnelApi.stroke(aID : TCanvasID): TCanvasError;
  1130. Var
  1131. C : TJSCanvasRenderingContext2D;
  1132. begin
  1133. {$IFNDEF NOLOGAPICALLS}
  1134. If LogAPICalls then
  1135. LogCall('Canvas.Stroke(%d)',[aID]);
  1136. {$ENDIF}
  1137. Result:=ECANVAS_NOCANVAS;
  1138. C:=GetCanvas(aID);
  1139. if Assigned(C) then
  1140. begin
  1141. C.Stroke;
  1142. Result:=ECANVAS_SUCCESS;
  1143. end;
  1144. end;
  1145. function TWasmFresnelApi.beginpath(aID : TCanvasID): TCanvasError;
  1146. Var
  1147. C : TJSCanvasRenderingContext2D;
  1148. begin
  1149. {$IFNDEF NOLOGAPICALLS}
  1150. If LogAPICalls then
  1151. LogCall('Canvas.BeginPath(%d)',[aID]);
  1152. {$ENDIF}
  1153. Result:=ECANVAS_NOCANVAS;
  1154. C:=GetCanvas(aID);
  1155. if Assigned(C) then
  1156. begin
  1157. C.beginPath;
  1158. Result:=ECANVAS_SUCCESS;
  1159. end;
  1160. end;
  1161. function TWasmFresnelApi.arc(aID: TCanvasID; X: Longint; Y: Longint; RadiusX,
  1162. RadiusY: Longint; StartAngle: Longint; EndAngle: Longint; Rotate: Longint;
  1163. Flags: Longint): TCanvasError;
  1164. Var
  1165. C : TJSCanvasRenderingContext2D;
  1166. begin
  1167. {$IFNDEF NOLOGAPICALLS}
  1168. If LogAPICalls then
  1169. LogCall('Canvas.Arc(%d,%d,%d,%d,%d,%f,%f)',[aID,X,Y,RadiusX,RadiusY,FresnelUnscale(StartAngle),FresnelUnscale(EndAngle)]);
  1170. {$ENDIF}
  1171. Result:=ECANVAS_NOCANVAS;
  1172. C:=GetCanvas(aID);
  1173. if Assigned(C) then
  1174. begin
  1175. C.beginPath;
  1176. if RadiusX=RadiusY then
  1177. C.Arc(X,y,RadiusX,FresnelUnscale(Startangle),FresnelUnscale(EndAngle))
  1178. else
  1179. C.Ellipse(X,y,RadiusX,RadiusY,FresnelUnScale(Rotate),FresnelUnscale(Startangle),FresnelUnscale(EndAngle));
  1180. if ((Flags and ARC_FILL)<>0) then
  1181. C.fill();
  1182. C.stroke();
  1183. Result:=ECANVAS_SUCCESS;
  1184. end;
  1185. end;
  1186. function TWasmFresnelApi.fillrect(aID : TCanvasID; X : Longint; Y : Longint; Width : Longint; Height : Longint): TCanvasError;
  1187. Var
  1188. C : TJSCanvasRenderingContext2D;
  1189. begin
  1190. {$IFNDEF NOLOGAPICALLS}
  1191. If LogAPICalls then
  1192. LogCall('Canvas.FillRect(%d,%d,%d,%d,%d)',[aID,X,Y,Width,Height]);
  1193. {$ENDIF}
  1194. Result:=ECANVAS_NOCANVAS;
  1195. C:=GetCanvas(aID);
  1196. if Assigned(C) then
  1197. begin
  1198. C.FillRect(X,y,width,Height);
  1199. Result:=ECANVAS_SUCCESS;
  1200. end;
  1201. end;
  1202. function TWasmFresnelApi.strokerect(aID : TCanvasID;X : Longint;Y : Longint; Width : Longint; Height : Longint ): TCanvasError;
  1203. Var
  1204. C : TJSCanvasRenderingContext2D;
  1205. begin
  1206. {$IFNDEF NOLOGAPICALLS}
  1207. If LogAPICalls then
  1208. LogCall('Canvas.StrokeRect(%d,%d,%d,%d,%d)',[aID,X,Y,Width,Height]);
  1209. {$ENDIF}
  1210. Result:=ECANVAS_NOCANVAS;
  1211. C:=GetCanvas(aID);
  1212. if Assigned(C) then
  1213. begin
  1214. C.StrokeRect(X,Y,Width,Height);
  1215. Result:=ECANVAS_SUCCESS;
  1216. end;
  1217. end;
  1218. function TWasmFresnelApi.clearrect(aID : TCanvasID;X : Longint;Y : Longint;Width : Longint; Height : Longint ): TCanvasError;
  1219. Var
  1220. C : TJSCanvasRenderingContext2D;
  1221. begin
  1222. {$IFNDEF NOLOGAPICALLS}
  1223. If LogAPICalls then
  1224. LogCall('Canvas.ClearRect(%d,%d,%d,%d,%d)',[aID,X,Y,Width,Height]);
  1225. {$ENDIF}
  1226. Result:=ECANVAS_NOCANVAS;
  1227. C:=GetCanvas(aID);
  1228. if Assigned(C) then
  1229. begin
  1230. C.ClearRect(X,Y,Width,Height);
  1231. Result:=ECANVAS_SUCCESS;
  1232. end;
  1233. end;
  1234. function TWasmFresnelApi.RoundRect(aID: TCanvasID; Flags: Longint; Data: TWasmPointer): TCanvasError;
  1235. Var
  1236. C : TJSCanvasRenderingContext2D;
  1237. V : TJSDataView;
  1238. X,Y,W,H : TFresnelFloat;
  1239. Radii : TJSArray;
  1240. Fill : Boolean;
  1241. function GetElement(aOffset : Longint) : TFresnelFloat;
  1242. begin
  1243. Result:=FresnelUnScale(V.getInt32(Data+(aOffset*4),Env.IsLittleEndian));
  1244. end;
  1245. Procedure AddRadius(aRX,aRY : Double);
  1246. begin
  1247. Radii.Push(New(['x',aRX,'y',aRY]))
  1248. end;
  1249. begin
  1250. {$IFNDEF NOLOGAPICALLS}
  1251. If LogAPICalls then
  1252. LogCall('Canvas.RoundRect(%d,%d,[%d])',[aID,Flags,Data]);
  1253. {$ENDIF}
  1254. C:=GetCanvas(aID);
  1255. if not Assigned(C) then
  1256. Exit(ECANVAS_NOCANVAS);
  1257. V:=getModuleMemoryDataView;
  1258. X:=GetElement(ROUNDRECT_BOXTOPLEFTX);
  1259. Y:=GetElement(ROUNDRECT_BOXTOPLEFTY);
  1260. W:=GetElement(ROUNDRECT_BOXBOTTOMRIGHTX)-X;
  1261. H:=GetElement(ROUNDRECT_BOXBOTTOMRIGHTY)-Y;
  1262. Fill:=(Flags and ROUNDRECT_FLAG_FILL)<>0;
  1263. Radii:=TJSArray.New;
  1264. AddRadius(GetElement(ROUNDRECT_RADIITOPLEFTX),GetElement(ROUNDRECT_RADIITOPLEFTY));
  1265. AddRadius(GetElement(ROUNDRECT_RADIITOPRIGHTX),GetElement(ROUNDRECT_RADIITOPRIGHTY));
  1266. AddRadius(GetElement(ROUNDRECT_RADIIBOTTOMRIGHTX),GetElement(ROUNDRECT_RADIIBOTTOMRIGHTY));
  1267. AddRadius(GetElement(ROUNDRECT_RADIIBOTTOMLEFTX),GetElement(ROUNDRECT_RADIIBOTTOMLEFTY));
  1268. C.BeginPath;
  1269. C.roundRect(X,Y,W,H,Radii);
  1270. if Fill then
  1271. C.fill;
  1272. C.stroke();
  1273. Result:=ECANVAS_SUCCESS;
  1274. end;
  1275. function TWasmFresnelApi.StrokeText(aID: TCanvasID; X: Longint; Y: Longint; aText: TWasmPointer; aTextLen: Longint): TCanvasError;
  1276. Var
  1277. C : TJSCanvasRenderingContext2D;
  1278. S : String;
  1279. begin
  1280. S:=Env.GetUTF8StringFromMem(aText,aTextLen);
  1281. {$IFNDEF NOLOGAPICALLS}
  1282. If LogAPICalls then
  1283. begin
  1284. LogCall('Canvas.StrokeText(%d,%d,%d,''%s'')',[aID,X,Y,S]);
  1285. end;
  1286. {$ENDIF}
  1287. Result:=ECANVAS_NOCANVAS;
  1288. C:=GetCanvas(aID);
  1289. if Assigned(C) then
  1290. begin
  1291. C.StrokeText(S,X,Y);
  1292. Result:=ECANVAS_SUCCESS;
  1293. end;
  1294. end;
  1295. function TWasmFresnelApi.FillText(aID: TCanvasID; X: Longint; Y: Longint; aText: TWasmPointer; aTextLen: Longint): TCanvasError;
  1296. Var
  1297. C : TJSCanvasRenderingContext2D;
  1298. S : String;
  1299. begin
  1300. S:=Env.GetUTF8StringFromMem(aText,aTextLen);
  1301. {$IFNDEF NOLOGAPICALLS}
  1302. If LogAPICalls then
  1303. begin
  1304. LogCall('Canvas.FillText(%d,%d,%d,''%s'')',[aID,X,Y,S]);
  1305. end;
  1306. {$ENDIF}
  1307. Result:=ECANVAS_NOCANVAS;
  1308. C:=GetCanvas(aID);
  1309. if Assigned(C) then
  1310. begin
  1311. S:=Env.GetUTF8StringFromMem(aText,aTextLen);
  1312. C.FillText(S,X,Y);
  1313. Result:=ECANVAS_SUCCESS;
  1314. end;
  1315. end;
  1316. end.