From 584e363110b921462ecf8276aaeea91b54ec8833 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Mon, 22 Jan 2018 09:26:14 -0800 Subject: [PATCH] Pass the tree edits to JS code on render --- .../src/Rendering/RenderComponentArgs.ts | 6 ++-- .../src/Rendering/RenderTreeEdit.ts | 29 +++++++++++++++++++ .../src/Rendering/Renderer.ts | 3 ++ .../Rendering/BrowserRenderer.cs | 8 ++++- 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderTreeEdit.ts diff --git a/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderComponentArgs.ts b/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderComponentArgs.ts index 5f5cea5485..a3684a0810 100644 --- a/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderComponentArgs.ts +++ b/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderComponentArgs.ts @@ -5,8 +5,10 @@ import { platform } from '../Environment'; export const renderComponentArgs = { browserRendererId: (obj: RenderComponentArgsPointer) => platform.readInt32Field(obj, 0), componentId: (obj: RenderComponentArgsPointer) => platform.readInt32Field(obj, 4), - renderTree: (obj: RenderComponentArgsPointer) => platform.readObjectField(obj, 8) as System_Array, - renderTreeLength: (obj: RenderComponentArgsPointer) => platform.readInt32Field(obj, 12), + renderTreeEdits: (obj: RenderComponentArgsPointer) => platform.readObjectField(obj, 8) as System_Array, + renderTreeEditsLength: (obj: RenderComponentArgsPointer) => platform.readInt32Field(obj, 12), + renderTree: (obj: RenderComponentArgsPointer) => platform.readObjectField(obj, 16) as System_Array, + renderTreeLength: (obj: RenderComponentArgsPointer) => platform.readInt32Field(obj, 20), } // Nominal type to ensure only valid pointers are passed to the renderComponentArgs functions. diff --git a/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderTreeEdit.ts b/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderTreeEdit.ts new file mode 100644 index 0000000000..2e2808ed24 --- /dev/null +++ b/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderTreeEdit.ts @@ -0,0 +1,29 @@ +import { System_Array, Pointer } from '../Platform/Platform'; +import { platform } from '../Environment'; +const renderTreeEditStructLength = 12; + +export function getRenderTreeEditPtr(renderTreeEdits: System_Array, index: number): RenderTreeEditPointer { + return platform.getArrayEntryPtr(renderTreeEdits, index, renderTreeEditStructLength) as RenderTreeEditPointer; +} + +export const renderTreeEdit = { + // The properties and memory layout must be kept in sync with the .NET equivalent in RenderTreeEdit.cs + type: (edit: RenderTreeEditPointer) => platform.readInt32Field(edit, 0) as EditType, + newTreeIndex: (edit: RenderTreeEditPointer) => platform.readInt32Field(edit, 4), + removedAttributeName: (edit: RenderTreeEditPointer) => platform.readStringField(edit, 8), +}; + +export enum EditType { + continue = 1, + prependNode = 2, + removeNode = 3, + setAttribute = 4, + removeAttribute = 5, + updateText = 6, + stepIn = 7, + stepOut = 8, +} + +// Nominal type to ensure only valid pointers are passed to the renderTreeEdit functions. +// At runtime the values are just numbers. +export interface RenderTreeEditPointer extends Pointer { RenderTreeEditPointer__DO_NOT_IMPLEMENT: any } diff --git a/src/Microsoft.Blazor.Browser.JS/src/Rendering/Renderer.ts b/src/Microsoft.Blazor.Browser.JS/src/Rendering/Renderer.ts index 6988731eed..5e29b9af43 100644 --- a/src/Microsoft.Blazor.Browser.JS/src/Rendering/Renderer.ts +++ b/src/Microsoft.Blazor.Browser.JS/src/Rendering/Renderer.ts @@ -1,6 +1,7 @@ import { System_Object, System_String, System_Array, MethodHandle, Pointer } from '../Platform/Platform'; import { platform } from '../Environment'; import { getTreeNodePtr, renderTreeNode, NodeType, RenderTreeNodePointer } from './RenderTreeNode'; +import { getRenderTreeEditPtr, renderTreeEdit, EditType, RenderTreeEditPointer } from './RenderTreeEdit'; import { renderComponentArgs, RenderComponentArgsPointer } from './RenderComponentArgs'; let raiseEventMethod: MethodHandle; let renderComponentMethod: MethodHandle; @@ -40,6 +41,8 @@ export function renderRenderTree(args: RenderComponentArgsPointer) { clearElement(element); + const edits = renderComponentArgs.renderTreeEdits(args); + const editsLength = renderComponentArgs.renderTreeEditsLength(args); const tree = renderComponentArgs.renderTree(args); const treeLength = renderComponentArgs.renderTreeLength(args); insertNodeRange(browserRendererId, componentId, element, tree, 0, treeLength - 1); diff --git a/src/Microsoft.Blazor.Browser/Rendering/BrowserRenderer.cs b/src/Microsoft.Blazor.Browser/Rendering/BrowserRenderer.cs index 333397f940..c38c0e149e 100644 --- a/src/Microsoft.Blazor.Browser/Rendering/BrowserRenderer.cs +++ b/src/Microsoft.Blazor.Browser/Rendering/BrowserRenderer.cs @@ -76,6 +76,8 @@ namespace Microsoft.Blazor.Browser.Rendering { BrowserRendererId = _browserRendererId, ComponentId = componentId, + RenderTreeEdits = renderTreeDiff.Edits.Array, + RenderTreeEditsLength = renderTreeDiff.Edits.Count, RenderTree = renderTreeDiff.CurrentState.Array, RenderTreeLength = renderTreeDiff.CurrentState.Count }); @@ -84,10 +86,14 @@ namespace Microsoft.Blazor.Browser.Rendering // Encapsulates the data we pass to the JS rendering function private struct RenderComponentArgs { + // Important: If you edit this struct, keep it in sync with RenderComponentArgs.ts + public int BrowserRendererId; public int ComponentId; + public RenderTreeEdit[] RenderTreeEdits; + public int RenderTreeEditsLength; public RenderTreeNode[] RenderTree; - public int RenderTreeLength; + public int RenderTreeLength; // TODO: Should be possible to remove this field once the JS code works entirely from the edits } } }