using Jint; using Jint.Native; using Progrart.Core.Graphics; using Progrart.Core.Storage; using System.Diagnostics; namespace Progrart.Core.JSExecution { public class ProgrartExecutor : IDisposable { public ExecutionEngine engine; public Dictionary ObjectPool = new(); public IStorageProvider StorageProvider; public ProgrartExecutor(IStorageProvider storageProvider) { engine = new ExecutionEngine(); SetupCalls(); StorageProvider = storageProvider; } public void SetupCalls() { Jint.Native.Json.JsonSerializer serializer = new Jint.Native.Json.JsonSerializer(engine.Engine); engine.Engine.SetValue("log", new Action((v) => { if (v is JsObject obj) { Trace.WriteLine(serializer.Serialize(obj)); } else Trace.WriteLine(v); })); engine.Engine.SetValue("require", (string str) => { require(str, () => { if (str.IndexOf(".") < 0) { require(str + ".progrart", () => { require(str + ".js", () => { throw new Exception("Module not found: " + str); }); }); } else { throw new Exception("Module not found: " + str); } }); }); engine.Engine.SetValue("visual_root", visual_root); engine.Engine.SetValue("line", line); engine.Engine.SetValue("rectangle", rectangle); engine.Engine.SetValue("rectangle", rectangle); engine.Engine.SetValue("oval", oval); engine.Engine.SetValue("triangle", triangle); engine.Engine.SetValue("path", path); engine.Engine.SetValue("path_element", path_element); engine.Engine.SetValue("circle", circle); engine.Engine.SetValue("color4", color4); engine.Engine.SetValue("color3", color3); engine.Engine.SetValue("text", text); engine.Engine.SetValue("color_hex", color_hex); engine.Engine.SetValue("linear_gradient", linear_gradient); engine.Engine.SetValue("radial_gradient", radial_gradient); } private void require(string str, Action onNoFound) { var task = StorageProvider.TryOpenRead(str); task.Wait(); var stream = task.GetAwaiter().GetResult(); if (stream is null) { onNoFound(); return; } using var sr = new StreamReader(stream); engine.Engine.Execute(sr.ReadToEnd()); } public JsObject color4(JsNumber r, JsNumber g, JsNumber b, JsNumber a) { return ProgrartFunctions.color(engine.Engine , r.AsNumber() , g.AsNumber() , b.AsNumber() , a.AsNumber() ); } public JsObject color3(JsNumber r, JsNumber g, JsNumber b) { return ProgrartFunctions.color(engine.Engine , r.AsNumber() , g.AsNumber() , b.AsNumber() ); } float colorFloat(byte b) => ((float)b / (float)byte.MaxValue); public JsObject color_hex(JsString colorString) { byte[] bytes = Convert.FromHexString(colorString.AsString()); if (bytes.Length == 3) return ProgrartFunctions.color(engine.Engine , colorFloat(bytes[0]) , colorFloat(bytes[1]) , colorFloat(bytes[2]) ); else if (bytes.Length == 4) return ProgrartFunctions.color(engine.Engine , colorFloat(bytes[0]) , colorFloat(bytes[1]) , colorFloat(bytes[2]) , colorFloat(bytes[3]) ); else throw new FormatException($"{colorString.AsString()} is not a recognizable color string!"); } public JsObject visual_root() { return ProgrartFunctions.CreateVisualRoot(this); } public JsObject line() => ProgrartFunctions.CreateElement(this); public JsObject rectangle() => ProgrartFunctions.CreateElement(this); public JsObject roundrect() => ProgrartFunctions.CreateElement(this); public JsObject path_element() => ProgrartFunctions.CreateElement(this); public JsObject path() => ProgrartFunctions.CreateElement(this); public JsObject circle() => ProgrartFunctions.CreateElement(this); public JsObject oval() => ProgrartFunctions.CreateElement(this); public JsObject triangle() => ProgrartFunctions.CreateElement(this); public JsObject text() => ProgrartFunctions.CreateElement(this); public RenderContext RenderImage(int Scale, string script, ExecuteArguments arguments) { float width = 1; float height = 1; engine.Symbols = arguments.data; engine.Execute(script); if (engine.Engine.GetValue("Width") is JsNumber js_width) { width = (float)(js_width.AsNumber()); } if (engine.Engine.GetValue("Height") is JsNumber js_height) { height = (float)(js_height.AsNumber()); } RenderContext renderContext = new((int)(width * Scale), (int)(height * Scale), StorageProvider) { LogicalW = width, LogicalH = height }; ImageRoot imageRoot = new ImageRoot(); var img = engine.Engine.Call("main"); if (ObjectPool[$"{img.Get("id")}"] is BaseElement element) imageRoot.Add(element); imageRoot.Render(renderContext); renderContext.canvas.Flush(); return renderContext; } public string RegisterObject(object obj) { string v = $"{obj.GetHashCode()}"; ObjectPool[v] = obj; return v; } public JsObject linear_gradient() => ProgrartFunctions.linear_gradient(engine.Engine); public JsObject radial_gradient() => ProgrartFunctions.radial_gradient(engine.Engine); public void Dispose() { engine.Dispose(); } } }