Skip to content

Commit

Permalink
perf: [Wasm] Improve UIElement.Visibility set to Collapsed
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromelaban committed May 7, 2021
1 parent 88b75d0 commit 0be67af
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 11 deletions.
12 changes: 1 addition & 11 deletions src/Uno.UI/UI/Xaml/UIElement.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -415,17 +415,7 @@ protected virtual void OnVisibilityChanged(Visibility oldValue, Visibility newVi
InvalidateMeasure();
UpdateHitTest();

if (newVisibility == Visibility.Visible)
{
ResetStyle("visibility");
}
else
{
// Note: On wasm when we have an 'hidden' (or 'collapsed') element, its height is used to compute the native 'scrollHeight',
// driving the SV to flicker when we scroll while at the bottom of the viewport (if those hidden element would have increase the viewport if visible).
// To avoid that, we move the element way out of the visible bounds of the view.
SetStyle(("visibility", "hidden"), ("top", "-100000px"), ("left", "-100000px"));
}
WindowManagerInterop.SetVisibility(HtmlId, newVisibility == Visibility.Visible);

if (FeatureConfiguration.UIElement.AssignDOMXamlProperties)
{
Expand Down
31 changes: 31 additions & 0 deletions src/Uno.UI/UI/Xaml/WindowManagerInterop.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,37 @@ private struct WindowManagerSetXUidParams
}
#endregion

#region SetVisibility

internal static void SetVisibility(IntPtr htmlId, bool visible)
{
if (UseJavascriptEval)
{
var command = $"Uno.UI.WindowManager.current.setVisibility(\"{htmlId}\", {visible});";
WebAssemblyRuntime.InvokeJS(command);
}
else
{
var parms = new WindowManagerSetVisibilityParams()
{
HtmlId = htmlId,
Visible = visible,
};

TSInteropMarshaller.InvokeJS("Uno:setVisibilityNative", parms);
}
}

[TSInteropMessage]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct WindowManagerSetVisibilityParams
{
public IntPtr HtmlId;

public bool Visible;
}
#endregion

#region SetProperty

internal static void SetProperty(IntPtr htmlId, (string name, string value)[] properties)
Expand Down
11 changes: 11 additions & 0 deletions src/Uno.UI/WasmCSS/Uno.UI.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ svg.uno-uielement {
position: fixed;
}

.uno-uielement.uno-visibility-collapsed {
/*
Note: On wasm when we have an 'hidden' (or 'collapsed') element, its height is used to compute the native 'scrollHeight',
driving the SV to flicker when we scroll while at the bottom of the viewport (if those hidden element would have increase the viewport if visible).
To avoid that, we move the element way out of the visible bounds of the view.
*/
visibility: hidden !important;
top: -100000px !important;
left: -100000px !important;
}

svg.uno-frameworkelement.uno-unarranged,
iframe.uno-frameworkelement.uno-unarranged,
img.uno-frameworkelement.uno-unarranged,
Expand Down
12 changes: 12 additions & 0 deletions src/Uno.UI/WasmScripts/Uno.UI.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ declare namespace Uno.UI {
static get isLoadEventsEnabled(): boolean;
private static readonly unoRootClassName;
private static readonly unoUnarrangedClassName;
private static readonly unoCollapsedClassName;
private static _cctor;
/**
* Initialize the WindowManager
Expand Down Expand Up @@ -227,6 +228,12 @@ declare namespace Uno.UI {
*/
setXUidNative(pParam: number): boolean;
private setXUidInternal;
/**
* Sets the visibility of the specified element
*/
setVisibility(elementId: number, visible: boolean): string;
setVisibilityNative(pParam: number): boolean;
private setVisibilityInternal;
/**
* Set an attribute for an element.
*/
Expand Down Expand Up @@ -1386,6 +1393,11 @@ declare class WindowManagerSetUnsetClassesParams {
CssClassesToUnset: Array<string>;
static unmarshal(pData: number): WindowManagerSetUnsetClassesParams;
}
declare class WindowManagerSetVisibilityParams {
HtmlId: number;
Visible: boolean;
static unmarshal(pData: number): WindowManagerSetVisibilityParams;
}
declare class WindowManagerSetXUidParams {
HtmlId: number;
Uid: string;
Expand Down
35 changes: 35 additions & 0 deletions src/Uno.UI/WasmScripts/Uno.UI.js
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,27 @@ var Uno;
setXUidInternal(elementId, name) {
this.getView(elementId).setAttribute("xuid", name);
}
/**
* Sets the visibility of the specified element
*/
setVisibility(elementId, visible) {
this.setVisibilityInternal(elementId, visible);
return "ok";
}
setVisibilityNative(pParam) {
const params = WindowManagerSetVisibilityParams.unmarshal(pParam);
this.setVisibilityInternal(params.HtmlId, params.Visible);
return true;
}
setVisibilityInternal(elementId, visible) {
const element = this.getView(elementId);
if (visible) {
element.classList.remove(WindowManager.unoCollapsedClassName);
}
else {
element.classList.add(WindowManager.unoCollapsedClassName);
}
}
/**
* Set an attribute for an element.
*/
Expand Down Expand Up @@ -1819,6 +1840,7 @@ var Uno;
WindowManager._isLoadEventsEnabled = false;
WindowManager.unoRootClassName = "uno-root-element";
WindowManager.unoUnarrangedClassName = "uno-unarranged";
WindowManager.unoCollapsedClassName = "uno-visibility-collapsed";
WindowManager._cctor = (() => {
WindowManager.initMethods();
UI.HtmlDom.initPolyfills();
Expand Down Expand Up @@ -5001,6 +5023,19 @@ class WindowManagerSetUnsetClassesParams {
}
}
/* TSBindingsGenerator Generated code -- this code is regenerated on each build */
class WindowManagerSetVisibilityParams {
static unmarshal(pData) {
const ret = new WindowManagerSetVisibilityParams();
{
ret.HtmlId = Number(Module.getValue(pData + 0, "*"));
}
{
ret.Visible = Boolean(Module.getValue(pData + 4, "i32"));
}
return ret;
}
}
/* TSBindingsGenerator Generated code -- this code is regenerated on each build */
class WindowManagerSetXUidParams {
static unmarshal(pData) {
const ret = new WindowManagerSetXUidParams();
Expand Down
26 changes: 26 additions & 0 deletions src/Uno.UI/ts/WindowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Uno.UI {

private static readonly unoRootClassName = "uno-root-element";
private static readonly unoUnarrangedClassName = "uno-unarranged";
private static readonly unoCollapsedClassName = "uno-visibility-collapsed";

private static _cctor = (() => {
WindowManager.initMethods();
Expand Down Expand Up @@ -364,6 +365,31 @@ namespace Uno.UI {
this.getView(elementId).setAttribute("xuid", name);
}

/**
* Sets the visibility of the specified element
*/
public setVisibility(elementId: number, visible: boolean): string {
this.setVisibilityInternal(elementId, visible);
return "ok";
}

public setVisibilityNative(pParam: number): boolean {
const params = WindowManagerSetVisibilityParams.unmarshal(pParam);
this.setVisibilityInternal(params.HtmlId, params.Visible);
return true;
}

private setVisibilityInternal(elementId: number, visible: boolean): void {
const element = this.getView(elementId);

if (visible) {
element.classList.remove(WindowManager.unoCollapsedClassName);
}
else {
element.classList.add(WindowManager.unoCollapsedClassName);
}
}

/**
* Set an attribute for an element.
*/
Expand Down
20 changes: 20 additions & 0 deletions src/Uno.UI/tsBindings/WindowManagerSetVisibilityParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* TSBindingsGenerator Generated code -- this code is regenerated on each build */
class WindowManagerSetVisibilityParams
{
/* Pack=4 */
public HtmlId : number;
public Visible : boolean;
public static unmarshal(pData:number) : WindowManagerSetVisibilityParams
{
const ret = new WindowManagerSetVisibilityParams();

{
ret.HtmlId = Number(Module.getValue(pData + 0, "*"));
}

{
ret.Visible = Boolean(Module.getValue(pData + 4, "i32"));
}
return ret;
}
}

0 comments on commit 0be67af

Please sign in to comment.