Browse Source

Merge branch 'features/blazorless-wasm' of github.com:AvaloniaUI/Avalonia into features/blazorless-wasm

pull/9028/head
Dan Walmsley 4 years ago
parent
commit
3e16701f83
  1. 1
      .gitignore
  2. 2
      src/Web/Avalonia.Web.Sample/index.html
  3. 8
      src/Web/Avalonia.Web/AvaloniaView.cs
  4. 46
      src/Web/Avalonia.Web/Interop/InputHelper.cs
  5. 55
      src/Web/Avalonia.Web/Interop/StreamHelper.cs
  6. 129
      src/Web/Avalonia.Web/Keycodes.cs
  7. 11
      src/Web/Avalonia.Web/RazorViewTopLevelImpl.cs
  8. 100
      src/Web/Avalonia.Web/Storage/BlobReadableStream.cs
  9. 136
      src/Web/Avalonia.Web/Storage/WriteableStream.cs
  10. 107
      src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts
  11. 4
      src/Web/Avalonia.Web/webapp/modules/avalonia/runtime.ts
  12. 124
      src/Web/Avalonia.Web/wwwroot/avalonia.js
  13. 10
      src/Web/Avalonia.Web/wwwroot/storage.js

1
.gitignore

@ -215,3 +215,4 @@ src/Web/Avalonia.Web.Blazor/Interop/Typescript/*.js
node_modules node_modules
src/Web/Avalonia.Web.Blazor/webapp/package-lock.json src/Web/Avalonia.Web.Blazor/webapp/package-lock.json
src/Web/Avalonia.Web.Blazor/wwwroot src/Web/Avalonia.Web.Blazor/wwwroot
src/Web/Avalonia.Web/wwwroot

2
src/Web/Avalonia.Web.Sample/index.html

@ -13,7 +13,7 @@
</head> </head>
<body> <body>
<div id="out"></div> <div id="out" tabindex="0"></div>
<script type='module' src="./main.js"></script> <script type='module' src="./main.js"></script>
</body> </body>

8
src/Web/Avalonia.Web/AvaloniaView.cs

@ -13,6 +13,8 @@ using Avalonia.Input.TextInput;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.Rendering.Composition; using Avalonia.Rendering.Composition;
using Avalonia.Web.Blazor; using Avalonia.Web.Blazor;
using Avalonia.Web.Interop;
using SkiaSharp; using SkiaSharp;
using static Avalonia.Web.AvaloniaRuntime; using static Avalonia.Web.AvaloniaRuntime;
@ -72,8 +74,10 @@ namespace Avalonia.Web
_topLevel.Renderer.Start(); _topLevel.Renderer.Start();
InputHelper.SubscribeKeyboardEvents(
div,
(code, key, modifier) => _topLevelImpl.RawKeyboardEvent(Input.Raw.RawKeyEventType.KeyDown, code, key, (Input.RawInputModifiers)modifier),
(code, key, modifier) => _topLevelImpl.RawKeyboardEvent(Input.Raw.RawKeyEventType.KeyUp, code, key, (Input.RawInputModifiers)modifier));
//_interop = new SKHtmlCanvasInterop(_avaloniaModule, _htmlCanvas, OnRenderFrame); //_interop = new SKHtmlCanvasInterop(_avaloniaModule, _htmlCanvas, OnRenderFrame);

46
src/Web/Avalonia.Web/Interop/InputHelper.cs

@ -0,0 +1,46 @@
using System;
using System.Runtime.InteropServices.JavaScript;
namespace Avalonia.Web.Interop;
internal static partial class InputHelper
{
//[JSImport("InputHelper.subscribePointerEvents", "avalonia.ts")]
//public static partial void SubscribePointerEvents(
// JSObject htmlElement,
// [JSMarshalAs<JSType.Function<JSType.Number, JSType.Number, JSType.Number, JSType.Number, JSType.Number, JSType.Boolean>>]
// Func<double, double, double, double, int, bool> wheel);
[JSImport("InputHelper.subscribeKeyboardEvents", "avalonia.ts")]
public static partial void SubscribeKeyboardEvents(
JSObject htmlElement,
[JSMarshalAs<JSType.Function<JSType.String, JSType.String, JSType.Number, JSType.Boolean>>]
Func<string, string, int, bool> keyDown,
[JSMarshalAs<JSType.Function<JSType.String, JSType.String, JSType.Number, JSType.Boolean>>]
Func<string, string, int, bool> keyUp);
[JSImport("InputHelper.subscribeInputEvents", "avalonia.ts")]
public static partial void SubscribeInputEvents(
JSObject htmlElement,
[JSMarshalAs<JSType.Function<JSType.String, JSType.Boolean>>]
Func<string, bool> input);
[JSImport("InputHelper.clearInput", "avalonia.ts")]
public static partial void ClearInputElement(JSObject htmlElement);
[JSImport("InputHelper.isInputElement", "avalonia.ts")]
public static partial void IsInputElement(JSObject htmlElement);
[JSImport("InputHelper.focusElement", "avalonia.ts")]
public static partial void FocusElement(JSObject htmlElement);
[JSImport("InputHelper.setCursor", "avalonia.ts")]
public static partial void SetCursor(JSObject htmlElement, string kind);
[JSImport("InputHelper.hide", "avalonia.ts")]
public static partial void HideElement(JSObject htmlElement);
[JSImport("InputHelper.show", "avalonia.ts")]
public static partial void ShowElement(JSObject htmlElement);
}

55
src/Web/Avalonia.Web/Interop/StreamHelper.cs

@ -0,0 +1,55 @@
using System;
using System.Runtime.InteropServices.JavaScript;
using System.Threading.Tasks;
namespace Avalonia.Web.Storage;
/// <summary>
/// Set of FileSystemWritableFileStream and Blob methods.
/// </summary>
internal static partial class StreamHelper
{
[JSImport("StreamHelper.seek", "avalonia.ts")]
public static partial void Seek(JSObject stream, [JSMarshalAs<JSType.Number>] long position);
[JSImport("StreamHelper.truncate", "avalonia.ts")]
public static partial void Truncate(JSObject stream, [JSMarshalAs<JSType.Number>] long position);
[JSImport("StreamHelper.write", "avalonia.ts")]
public static partial void Write(JSObject stream, [JSMarshalAs<JSType.MemoryView>] Span<byte> data);
[JSImport("StreamHelper.write", "avalonia.ts")]
public static partial Task WriteAsync(JSObject stream, [JSMarshalAs<JSType.MemoryView>] ArraySegment<byte> data);
[JSImport("StreamHelper.close", "avalonia.ts")]
public static partial void Close(JSObject stream);
[JSImport("StreamHelper.close", "avalonia.ts")]
public static partial Task CloseAsync(JSObject stream);
[JSImport("StreamHelper.size", "avalonia.ts")]
[return: JSMarshalAs<JSType.Number>]
public static partial long Size(JSObject stream);
[JSImport("StreamHelper.byteLength", "avalonia.ts")]
[return: JSMarshalAs<JSType.Number>]
public static partial long ByteLength(JSObject stream);
[JSImport("StreamHelper.sliceToArray", "avalonia.ts")]
[return: JSMarshalAs<JSType.MemoryView>]
public static partial Span<byte> Slice(JSObject stream, [JSMarshalAs<JSType.Number>] long offset, int count);
public static async Task<ArraySegment<byte>> SliceAsync(JSObject stream, long offset, int count)
{
using var buffer = await SliceToBufferAsync(stream, offset, count);
return BufferToArray(buffer);
}
[JSImport("StreamHelper.slice", "avalonia.ts")]
[return: JSMarshalAs<JSType.Promise<JSType.Object>>]
private static partial Task<JSObject> SliceToBufferAsync(JSObject stream, [JSMarshalAs<JSType.Number>] long offset, int count);
[JSImport("StreamHelper.toArray", "avalonia.ts")]
[return: JSMarshalAs<JSType.MemoryView>]
private static partial ArraySegment<byte> BufferToArray(JSObject stream);
}

129
src/Web/Avalonia.Web/Keycodes.cs

@ -0,0 +1,129 @@
using System.Collections.Generic;
using Avalonia.Input;
namespace Avalonia.Web
{
internal static class Keycodes
{
public static Dictionary<string, Key> KeyCodes = new()
{
{ "Escape", Key.Escape },
{ "Digit1", Key.D1 },
{ "Digit2", Key.D2 },
{ "Digit3", Key.D3 },
{ "Digit4", Key.D4 },
{ "Digit5", Key.D5 },
{ "Digit6", Key.D6 },
{ "Digit7", Key.D7 },
{ "Digit8", Key.D8 },
{ "Digit9", Key.D9 },
{ "Digit0", Key.D0 },
{ "Minus", Key.OemMinus },
//{ "Equal" , Key. },
{ "Backspace", Key.Back },
{ "Tab", Key.Tab },
{ "KeyQ", Key.Q },
{ "KeyW", Key.W },
{ "KeyE", Key.E },
{ "KeyR", Key.R },
{ "KeyT", Key.T },
{ "KeyY", Key.Y },
{ "KeyU", Key.U },
{ "KeyI", Key.I },
{ "KeyO", Key.O },
{ "KeyP", Key.P },
{ "BracketLeft", Key.OemOpenBrackets },
{ "BracketRight", Key.OemCloseBrackets },
{ "Enter", Key.Enter },
{ "ControlLeft", Key.LeftCtrl },
{ "KeyA", Key.A },
{ "KeyS", Key.S },
{ "KeyD", Key.D },
{ "KeyF", Key.F },
{ "KeyG", Key.G },
{ "KeyH", Key.H },
{ "KeyJ", Key.J },
{ "KeyK", Key.K },
{ "KeyL", Key.L },
{ "Semicolon", Key.OemSemicolon },
{ "Quote", Key.OemQuotes },
//{ "Backquote" , Key. },
{ "ShiftLeft", Key.LeftShift },
{ "Backslash", Key.OemBackslash },
{ "KeyZ", Key.Z },
{ "KeyX", Key.X },
{ "KeyC", Key.C },
{ "KeyV", Key.V },
{ "KeyB", Key.B },
{ "KeyN", Key.N },
{ "KeyM", Key.M },
{ "Comma", Key.OemComma },
{ "Period", Key.OemPeriod },
//{ "Slash" , Key. },
{ "ShiftRight", Key.RightShift },
{ "NumpadMultiply", Key.Multiply },
{ "AltLeft", Key.LeftAlt },
{ "Space", Key.Space },
{ "CapsLock", Key.CapsLock },
{ "F1", Key.F1 },
{ "F2", Key.F2 },
{ "F3", Key.F3 },
{ "F4", Key.F4 },
{ "F5", Key.F5 },
{ "F6", Key.F6 },
{ "F7", Key.F7 },
{ "F8", Key.F8 },
{ "F9", Key.F9 },
{ "F10", Key.F10 },
{ "NumLock", Key.NumLock },
{ "ScrollLock", Key.Scroll },
{ "Numpad7", Key.NumPad7 },
{ "Numpad8", Key.NumPad8 },
{ "Numpad9", Key.NumPad9 },
{ "NumpadSubtract", Key.Subtract },
{ "Numpad4", Key.NumPad4 },
{ "Numpad5", Key.NumPad5 },
{ "Numpad6", Key.NumPad6 },
{ "NumpadAdd", Key.Add },
{ "Numpad1", Key.NumPad1 },
{ "Numpad2", Key.NumPad2 },
{ "Numpad3", Key.NumPad3 },
{ "Numpad0", Key.NumPad0 },
{ "NumpadDecimal", Key.Decimal },
{ "Unidentified", Key.NoName },
//{ "IntlBackslash" , Key.bac },
{ "F11", Key.F11 },
{ "F12", Key.F12 },
//{ "IntlRo" , Key.Ro },
//{ "Unidentified" , Key. },
{ "Convert", Key.ImeConvert },
{ "KanaMode", Key.KanaMode },
{ "NonConvert", Key.ImeNonConvert },
//{ "Unidentified" , Key. },
{ "NumpadEnter", Key.Enter },
{ "ControlRight", Key.RightCtrl },
{ "NumpadDivide", Key.Divide },
{ "PrintScreen", Key.PrintScreen },
{ "AltRight", Key.RightAlt },
//{ "Unidentified" , Key. },
{ "Home", Key.Home },
{ "ArrowUp", Key.Up },
{ "PageUp", Key.PageUp },
{ "ArrowLeft", Key.Left },
{ "ArrowRight", Key.Right },
{ "End", Key.End },
{ "ArrowDown", Key.Down },
{ "PageDown", Key.PageDown },
{ "Insert", Key.Insert },
{ "Delete", Key.Delete },
//{ "Unidentified" , Key. },
{ "AudioVolumeMute", Key.VolumeMute },
{ "AudioVolumeDown", Key.VolumeDown },
{ "AudioVolumeUp", Key.VolumeUp },
//{ "NumpadEqual" , Key. },
{ "Pause", Key.Pause },
{ "NumpadComma", Key.OemComma }
};
}
}

11
src/Web/Avalonia.Web/RazorViewTopLevelImpl.cs

@ -110,14 +110,15 @@ namespace Avalonia.Web.Blazor
public bool RawKeyboardEvent(RawKeyEventType type, string code, string key, RawInputModifiers modifiers) public bool RawKeyboardEvent(RawKeyEventType type, string code, string key, RawInputModifiers modifiers)
{ {
/*if (Keycodes.KeyCodes.TryGetValue(code, out var avkey)) Console.WriteLine($"{type} {code} {key} {modifiers}");
if (Keycodes.KeyCodes.TryGetValue(code, out var avkey))
{ {
if (_inputRoot is { }) if (_inputRoot is { })
{ {
var args = new RawKeyEventArgs(KeyboardDevice, Timestamp, _inputRoot, type, avkey, modifiers); var args = new RawKeyEventArgs(KeyboardDevice, Timestamp, _inputRoot, type, avkey, modifiers);
Input?.Invoke(args); Input?.Invoke(args);
return args.Handled; return args.Handled;
} }
} }
@ -126,12 +127,12 @@ namespace Avalonia.Web.Blazor
if (_inputRoot is { }) if (_inputRoot is { })
{ {
var args = new RawKeyEventArgs(KeyboardDevice, Timestamp, _inputRoot, type, avkey, modifiers); var args = new RawKeyEventArgs(KeyboardDevice, Timestamp, _inputRoot, type, avkey, modifiers);
Input?.Invoke(args); Input?.Invoke(args);
return args.Handled; return args.Handled;
} }
}*/ }
return false; return false;
} }

100
src/Web/Avalonia.Web/Storage/BlobReadableStream.cs

@ -0,0 +1,100 @@
using System;
using System.IO;
using System.Runtime.InteropServices.JavaScript;
using System.Threading;
using System.Threading.Tasks;
namespace Avalonia.Web.Storage;
internal class BlobReadableStream : Stream
{
private JSObject? _jSReference;
private long _position;
private readonly long _length;
public BlobReadableStream(JSObject jsStreamReference)
{
_jSReference = jsStreamReference;
_position = 0;
_length = StreamHelper.ByteLength(JSReference);
}
private JSObject JSReference => _jSReference ?? throw new ObjectDisposedException(nameof(JSWriteableStream));
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => _length;
public override long Position
{
get => _position;
set => throw new NotSupportedException();
}
public override void Flush() { }
public override long Seek(long offset, SeekOrigin origin)
{
return _position = origin switch
{
SeekOrigin.Current => _position + offset,
SeekOrigin.End => _length + offset,
_ => offset
};
}
public override void SetLength(long value)
=> throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count)
=> throw new NotSupportedException();
public override int Read(byte[] buffer, int offset, int count)
=> Read(buffer.AsSpan(offset, count));
public override int Read(Span<byte> buffer)
{
var numBytesToRead = (int)Math.Min(buffer.Length, Length - _position);
var bytesRead = StreamHelper.Slice(JSReference, _position, numBytesToRead);
if (bytesRead.Length != numBytesToRead)
{
throw new EndOfStreamException("Failed to read the requested number of bytes from the stream.");
}
_position += bytesRead.Length;
bytesRead.CopyTo(buffer);
return bytesRead.Length;
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
=> await ReadAsync(buffer.AsMemory(offset, count), cancellationToken);
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
var numBytesToRead = (int)Math.Min(buffer.Length, Length - _position);
var bytesRead = await StreamHelper.SliceAsync(JSReference, _position, numBytesToRead);
if (bytesRead.Count != numBytesToRead)
{
throw new EndOfStreamException("Failed to read the requested number of bytes from the stream.");
}
_position += bytesRead.Count;
bytesRead.AsMemory().CopyTo(buffer);
return bytesRead.Count;
}
protected override void Dispose(bool disposing)
{
if (_jSReference is { } jsReference)
{
_jSReference = null;
jsReference.Dispose();
}
}
}

136
src/Web/Avalonia.Web/Storage/WriteableStream.cs

@ -0,0 +1,136 @@
using System;
using System.IO;
using System.Runtime.InteropServices.JavaScript;
using System.Threading;
using System.Threading.Tasks;
namespace Avalonia.Web.Storage;
// Loose wrapper implementaion of a stream on top of FileAPI FileSystemWritableFileStream
internal sealed class JSWriteableStream : Stream
{
private JSObject? _jSReference;
// Unfortunatelly we can't read current length/position, so we need to keep it C#-side only.
private long _length, _position;
internal JSWriteableStream(JSObject jSReference, long initialLength)
{
_jSReference = jSReference;
_length = initialLength;
}
private JSObject JSReference => _jSReference ?? throw new ObjectDisposedException(nameof(JSWriteableStream));
public override bool CanRead => false;
public override bool CanSeek => true;
public override bool CanWrite => true;
public override long Length => _length;
public override long Position
{
get => _position;
set => Seek(_position, SeekOrigin.Begin);
}
public override void Flush()
{
// no-op
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
var position = origin switch
{
SeekOrigin.Current => _position + offset,
SeekOrigin.End => _length + offset,
_ => offset
};
StreamHelper.Seek(JSReference, position);
return position;
}
public override void SetLength(long value)
{
_length = value;
// See https://docs.w3cub.com/dom/filesystemwritablefilestream/truncate
// If the offset is smaller than the size, it remains unchanged. If the offset is larger than size, the offset is set to that size
if (_position > _length)
{
_position = _length;
}
StreamHelper.Truncate(JSReference, value);
}
public override void Write(byte[] buffer, int offset, int count)
{
StreamHelper.Write(JSReference, buffer.AsSpan(offset, count));
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (offset != 0 || count != buffer.Length)
{
// TODO, we need to pass prepared buffer to the JS
// Can't use ArrayPool as it can return bigger array than requested
// Can't use Span/Memory, as it's not supported by JS interop yet.
// Alternatively we can pass original buffer and offset+count, so it can be trimmed on the JS side (but is it more efficient tho?)
buffer = buffer.AsMemory(offset, count).ToArray();
}
return WriteAsyncInternal(buffer, cancellationToken);
}
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
return new ValueTask(WriteAsyncInternal(buffer.ToArray(), cancellationToken));
}
private Task WriteAsyncInternal(byte[] buffer, CancellationToken _)
{
_position += buffer.Length;
return StreamHelper.WriteAsync(JSReference, buffer);
}
protected override void Dispose(bool disposing)
{
if (_jSReference is { } jsReference)
{
_jSReference = null;
try
{
StreamHelper.Close(JSReference);
}
finally
{
jsReference.Dispose();
}
}
}
public override async ValueTask DisposeAsync()
{
if (_jSReference is { } jsReference)
{
_jSReference = null;
try
{
await StreamHelper.CloseAsync(JSReference);
}
finally
{
jsReference.Dispose();
}
}
}
}

107
src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts

@ -0,0 +1,107 @@
enum RawInputModifiers
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Meta = 8,
LeftMouseButton = 16,
RightMouseButton = 32,
MiddleMouseButton = 64,
XButton1MouseButton = 128,
XButton2MouseButton = 256,
KeyboardMask = Alt | Control | Shift | Meta,
PenInverted = 512,
PenEraser = 1024,
PenBarrelButton = 2048
}
export class InputHelper {
public static subscribeKeyboardEvents(
element: HTMLInputElement,
keyDownCallback: (code: string, key: string, modifiers: RawInputModifiers) => boolean,
keyUpCallback: (code: string, key: string, modifiers: RawInputModifiers) => boolean,
) {
const keyDownHandler = (args: Event) => {
const keyArgs = <KeyboardEvent>args;
if (keyDownCallback(keyArgs.code, keyArgs.key, this.getModifiers(keyArgs))) {
args.preventDefault();
}
};
element.addEventListener("keydown", keyDownHandler);
const keyUpHandler = (args: Event) => {
const keyArgs = <KeyboardEvent>args;
if (keyUpCallback(keyArgs.code, keyArgs.key, this.getModifiers(keyArgs))) {
args.preventDefault();
}
};
element.addEventListener("keyup", keyUpHandler);
return () => {
element.removeEventListener("keydown", keyDownHandler);
element.removeEventListener("keyup", keyUpHandler);
};
}
public static subscribeInputEvents(
element: HTMLInputElement,
inputCallback: (value: string) => boolean
) {
const inputHandler = (args: Event) => {
if (inputCallback((args as any).value)) {
args.preventDefault();
}
};
element.addEventListener("input", inputHandler);
return () => {
element.removeEventListener("input", inputHandler);
};
}
public static clearInput(inputElement: HTMLInputElement) {
inputElement.value = "";
}
public static isInputElement(element: HTMLInputElement | HTMLElement): element is HTMLInputElement {
return (element as HTMLInputElement).setSelectionRange !== undefined;
}
public static focusElement(inputElement: HTMLElement) {
inputElement.focus();
if (this.isInputElement(inputElement)) {
(inputElement as HTMLInputElement).setSelectionRange(0, 0);
}
}
public static setCursor(inputElement: HTMLInputElement, kind: string) {
inputElement.style.cursor = kind;
}
public static hide(inputElement: HTMLInputElement) {
inputElement.style.display = 'none';
}
public static show(inputElement: HTMLInputElement) {
inputElement.style.display = 'block';
}
private static getModifiers(args: KeyboardEvent): RawInputModifiers {
var modifiers = RawInputModifiers.None;
if (args.ctrlKey)
modifiers |= RawInputModifiers.Control;
if (args.altKey)
modifiers |= RawInputModifiers.Alt;
if (args.shiftKey)
modifiers |= RawInputModifiers.Shift;
if (args.metaKey)
modifiers |= RawInputModifiers.Meta;
return modifiers;
}
}

4
src/Web/Avalonia.Web/webapp/modules/avalonia/runtime.ts

@ -1,6 +1,7 @@
import { RuntimeAPI } from "../../types/dotnet"; import { RuntimeAPI } from "../../types/dotnet";
import { Canvas } from "./canvas"; import { Canvas } from "./canvas";
import { InputHelper } from "./input";
export class AvaloniaRuntime { export class AvaloniaRuntime {
constructor( constructor(
@ -8,7 +9,8 @@ export class AvaloniaRuntime {
api: RuntimeAPI api: RuntimeAPI
) { ) {
api.setModuleImports("avalonia.ts", { api.setModuleImports("avalonia.ts", {
Canvas Canvas,
InputHelper
}); });
} }
} }

124
src/Web/Avalonia.Web/wwwroot/avalonia.js

@ -1,124 +0,0 @@
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// modules/avalonia/canvas.ts
var Canvas = class {
constructor(useGL, element) {
this.renderLoopEnabled = false;
this.renderLoopRequest = 0;
if (useGL) {
const ctx = Canvas.createWebGLContext(element);
if (!ctx) {
console.error(`Failed to create WebGL context: err ${ctx}`);
return;
}
var GL = globalThis.AvaloniaGL;
GL.makeContextCurrent(ctx);
var GLctx = GL.currentContext.GLctx;
const fbo = GLctx.getParameter(GLctx.FRAMEBUFFER_BINDING);
this.glInfo = {
context: ctx,
fboId: fbo ? fbo.id : 0,
stencil: GLctx.getParameter(GLctx.STENCIL_BITS),
sample: 0,
depth: GLctx.getParameter(GLctx.DEPTH_BITS)
};
}
}
static createCanvas(element) {
var canvas = document.createElement("canvas");
element.appendChild(canvas);
return canvas;
}
static initGL(element, elementId) {
console.log("inside initGL");
var view = Canvas.init(true, element, elementId);
if (!view || !view.glInfo)
return null;
return view.glInfo;
}
static init(useGL, element, elementId) {
var htmlCanvas = element;
if (!htmlCanvas) {
console.error(`No canvas element was provided.`);
return null;
}
if (!Canvas.elements)
Canvas.elements = /* @__PURE__ */ new Map();
Canvas.elements.set(elementId, element);
const view = new Canvas(useGL, element);
htmlCanvas.SKHtmlCanvas = view;
return view;
}
static Foo(canvas) {
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 150, 75);
}
static createWebGLContext(htmlCanvas) {
const contextAttributes = {
alpha: 1,
depth: 1,
stencil: 8,
antialias: 0,
premultipliedAlpha: 1,
preserveDrawingBuffer: 0,
preferLowPowerToHighPerformance: 0,
failIfMajorPerformanceCaveat: 0,
majorVersion: 2,
minorVersion: 0,
enableExtensionsByDefault: 1,
explicitSwapControl: 0,
renderViaOffscreenBackBuffer: 1
};
var GL = globalThis.AvaloniaGL;
let ctx = GL.createContext(htmlCanvas, contextAttributes);
if (!ctx && contextAttributes.majorVersion > 1) {
console.warn("Falling back to WebGL 1.0");
contextAttributes.majorVersion = 1;
contextAttributes.minorVersion = 0;
ctx = GL.createContext(htmlCanvas, contextAttributes);
}
return ctx;
}
};
// modules/avalonia/runtime.ts
var AvaloniaRuntime = class {
constructor(dotnetAssembly, api) {
this.dotnetAssembly = dotnetAssembly;
api.setModuleImports("avalonia.ts", {
Canvas
});
}
};
// modules/avalonia.ts
function createAvaloniaRuntime(api) {
return __async(this, null, function* () {
const dotnetAssembly = yield api.getAssemblyExports("Avalonia.Web.dll");
return new AvaloniaRuntime(dotnetAssembly, api);
});
}
export {
createAvaloniaRuntime
};
//# sourceMappingURL=avalonia.js.map

10
src/Web/Avalonia.Web/wwwroot/storage.js

@ -1,10 +0,0 @@
// modules/storage.ts
var StorageProvider = class {
static isFileApiSupported() {
return globalThis.showOpenFilePicker !== void 0;
}
};
export {
StorageProvider
};
//# sourceMappingURL=storage.js.map
Loading…
Cancel
Save