Skip to content

Commit

Permalink
fix(unowasm): Adds missing Uno.WinUI javascript support file (#2086)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromelaban committed May 30, 2022
1 parent d6a1f56 commit d6ae135
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ namespace SkiaSharp.Views.UWP
[HtmlElement("canvas")]
public partial class SKSwapChainPanel : FrameworkElement
{
#if HAS_UNO_WINUI
const string SKSwapChainPanelTypeFullName = "SkiaSharp.Views.Windows." + nameof(SKSwapChainPanel);
#else
const string SKSwapChainPanelTypeFullName = "SkiaSharp.Views.UWP" + nameof(SKSwapChainPanel);
#endif

private const int ResourceCacheBytes = 256 * 1024 * 1024; // 256 MB
private const SKColorType colorType = SKColorType.Rgba8888;
private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft;
Expand Down Expand Up @@ -192,15 +198,15 @@ public JsInfo CreateContext()

long IJSObjectMetadata.CreateNativeInstance(IntPtr managedHandle)
{
WebAssemblyRuntime.InvokeJS($"SkiaSharp.Views.UWP.SKSwapChainPanel.createInstance('{managedHandle}', '{jsHandle}')");
WebAssemblyRuntime.InvokeJS(SKSwapChainPanelTypeFullName + $".createInstance('{managedHandle}', '{jsHandle}')");
return jsHandle;
}

string IJSObjectMetadata.GetNativeInstance(IntPtr managedHandle, long jsHandle) =>
$"SkiaSharp.Views.UWP.SKSwapChainPanel.getInstance('{jsHandle}')";
SKSwapChainPanelTypeFullName + $".getInstance('{jsHandle}')";

void IJSObjectMetadata.DestroyNativeInstance(IntPtr managedHandle, long jsHandle) =>
WebAssemblyRuntime.InvokeJS($"SkiaSharp.Views.UWP.SKSwapChainPanel.destroyInstance('{jsHandle}')");
WebAssemblyRuntime.InvokeJS(SKSwapChainPanelTypeFullName + $".destroyInstance('{jsHandle}')");

object IJSObjectMetadata.InvokeManaged(object instance, string method, string parameters)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ namespace SkiaSharp.Views.UWP
[HtmlElement("canvas")]
public partial class SKXamlCanvas
{
#if HAS_UNO_WINUI
const string SKXamlCanvasFullTypeName = "SkiaSharp.Views.Windows." + nameof(SKXamlCanvas);
#else
const string SKXamlCanvasFullTypeName = "SkiaSharp.Views.UWP." + nameof(SKXamlCanvas);
#endif

private byte[] pixels;
private GCHandle pixelsHandle;
private int pixelWidth;
Expand Down Expand Up @@ -61,7 +67,7 @@ private void DoInvalidate()
OnPaintSurface(new SKPaintSurfaceEventArgs(surface, info.WithSize(userVisibleSize), info));
}

WebAssemblyRuntime.InvokeJS($"SkiaSharp.Views.UWP.SKXamlCanvas.invalidateCanvas({pixelsHandle.AddrOfPinnedObject()}, \"{this.GetHtmlId()}\", {info.Width}, {pixelHeight});");
WebAssemblyRuntime.InvokeJS(SKXamlCanvasFullTypeName + $".invalidateCanvas({pixelsHandle.AddrOfPinnedObject()}, \"{this.GetHtmlId()}\", {info.Width}, {pixelHeight});");
}

private SKImageInfo CreateBitmap(out SKSizeI unscaledSize, out float dpi)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
</ItemGroup>
<ItemGroup>
<None Remove="nuget\build\netstandard2.0\SkiaSharp.Views.Uno.WinUI.targets" />
<None Remove="WasmScripts\SkiaSharp.Views.Uno.Wasm.js" />
<None Include="nuget\build\netstandard2.0\SkiaSharp.Views.Uno.WinUI.targets" Link="nuget\build\$(PackagingPlatform)\SkiaSharp.Views.Uno.WinUI.targets" />
</ItemGroup>
<ItemGroup>
Expand All @@ -32,5 +33,6 @@
<EmbeddedResource Include="..\SkiaSharp.Views.Uno.Wasm\LinkerDefinition.Wasm.xml">
<LogicalName>$(AssemblyName).xml</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="WasmScripts\SkiaSharp.Views.Uno.Wasm.js" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
var SkiaSharp;
(function (SkiaSharp) {
var Views;
(function (Views) {
var Windows;
(function (Windows) {

class SKXamlCanvas {
static invalidateCanvas(pData, canvasId, width, height) {
var htmlCanvas = document.getElementById(canvasId);
htmlCanvas.width = width;
htmlCanvas.height = height;

var ctx = htmlCanvas.getContext('2d');
if (!ctx)
return false;

var buffer = new Uint8ClampedArray(Module.HEAPU8.buffer, pData, width * height * 4);
var imageData = new ImageData(buffer, width, height);
ctx.putImageData(imageData, 0, 0);

return true;
}
}

class SKSwapChainPanel {
static activeInstances = {};

constructor(managedHandle) {
this.managedHandle = managedHandle;
this.canvas = undefined;
this.jsInfo = undefined;
this.renderLoop = false;
this.currentRequest = 0;
}

// JSObject
static createInstance(managedHandle, jsHandle) {
SKSwapChainPanel.activeInstances[jsHandle] = new SKSwapChainPanel(managedHandle);
}
static getInstance(jsHandle) {
return SKSwapChainPanel.activeInstances[jsHandle];
}
static destroyInstance(jsHandle) {
delete SKSwapChainPanel.activeInstances[jsHandle];
}

requestAnimationFrame(renderLoop) {
// optionally update the render loop
if (renderLoop !== undefined && this.renderLoop !== renderLoop)
this.setEnableRenderLoop(renderLoop);

// skip because we have a render loop
if (this.currentRequest !== 0)
return;

// make sure the canvas is scaled correctly for the drawing
this.resizeCanvas();

// add the draw to the next frame
this.currentRequest = window.requestAnimationFrame(() => {
Uno.Foundation.Interop.ManagedObject.dispatch(this.managedHandle, 'RenderFrame', null);

this.currentRequest = 0;

// we may want to draw the next frame
if (this.renderLoop)
this.requestAnimationFrame();
});
}

resizeCanvas() {
if (!this.canvas)
return;

var scale = window.devicePixelRatio || 1;
var w = this.canvas.clientWidth * scale
var h = this.canvas.clientHeight * scale;

if (this.canvas.width !== w)
this.canvas.width = w;
if (this.canvas.height !== h)
this.canvas.height = h;
}

setEnableRenderLoop(enable) {
this.renderLoop = enable;

// either start the new frame or cancel the existing one
if (enable) {
this.requestAnimationFrame();
} else if (this.currentRequest !== 0) {
window.cancelAnimationFrame(this.currentRequest);
this.currentRequest = 0;
}
}

createContext(canvasOrCanvasId) {
if (!canvasOrCanvasId)
throw 'No <canvas> element or ID was provided';

var canvas = canvasOrCanvasId;
if (canvas.tagName !== 'CANVAS') {
canvas = document.getElementById(canvasOrCanvasId);
if (!canvas)
throw `No <canvas> with id ${canvasOrCanvasId} was found`;
}

var ctx = SKSwapChainPanel.createWebGLContext(canvas);
if (!ctx || ctx < 0)
throw `Failed to create WebGL context: err ${ctx}`;

// make current
GL.makeContextCurrent(ctx);

// read values
this.canvas = canvas;
var info = {
ctx: ctx,
fbo: GLctx.getParameter(GLctx.FRAMEBUFFER_BINDING),
stencil: GLctx.getParameter(GLctx.STENCIL_BITS),
sample: 0, // TODO: GLctx.getParameter(GLctx.SAMPLES)
depth: GLctx.getParameter(GLctx.DEPTH_BITS),
};

// format as array for nicer parsing
this.jsInfo = [
info.ctx,
info.fbo ? info.fbo.id : 0,
info.stencil,
info.sample,
info.depth,
];
return this.jsInfo;
}

static createWebGLContext(canvas) {
var contextAttributes = {
alpha: 1,
depth: 1,
stencil: 8,
antialias: 1,
premultipliedAlpha: 1,
preserveDrawingBuffer: 0,
preferLowPowerToHighPerformance: 0,
failIfMajorPerformanceCaveat: 0,
majorVersion: 2,
minorVersion: 0,
enableExtensionsByDefault: 1,
explicitSwapControl: 0,
renderViaOffscreenBackBuffer: 0,
};

var ctx = GL.createContext(canvas, contextAttributes);
if (!ctx && contextAttributes.majorVersion > 1) {
console.warn('Falling back to WebGL 1.0');
contextAttributes.majorVersion = 1;
contextAttributes.minorVersion = 0;
ctx = GL.createContext(canvas, contextAttributes);
}

return ctx;
}
}

Windows.SKXamlCanvas = SKXamlCanvas;
Windows.SKSwapChainPanel = SKSwapChainPanel;

})(Windows = Views.Windows || (Views.Windows = {}));
})(Views = SkiaSharp.Views || (SkiaSharp.Views = {}));
})(SkiaSharp || (SkiaSharp = {}));

0 comments on commit d6ae135

Please sign in to comment.