From ef317d141756f380c31daae7bd418e6f4cb9f134 Mon Sep 17 00:00:00 2001 From: Phap Dieu Duong Date: Wed, 29 Jan 2025 13:04:51 +0700 Subject: [PATCH] Webview2 SVG: support checkerboard only within the image region #2076 --- .../src/DXCanvas_Webview2/HapplaBoxViewer.ts | 14 +++++ .../webComponents/happlajs/HapplaBox.ts | 12 +++- .../webComponents/happlajs/HapplaBoxTypes.ts | 1 + Source/Components/ImageGlass.Views/Enums.cs | 1 + .../ImageGlass.Views/ViewerCanvas.cs | 15 +++-- .../ImageGlass.Views/ViewerCanvas_Webview2.cs | 56 +++++++++++++++++-- 6 files changed, 88 insertions(+), 11 deletions(-) diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/HapplaBoxViewer.ts b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/HapplaBoxViewer.ts index 3472024b7..c3df135f1 100644 --- a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/HapplaBoxViewer.ts +++ b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/HapplaBoxViewer.ts @@ -24,6 +24,7 @@ enum Web2FrontendMsgNames { ON_ZOOM_CHANGED = 'ON_ZOOM_CHANGED', ON_POINTER_DOWN = 'ON_POINTER_DOWN', ON_MOUSE_WHEEL = 'ON_MOUSE_WHEEL', + ON_CONTENT_SIZE_CHANGED = 'ON_CONTENT_SIZE_CHANGED', ON_FILE_DROP = 'ON_FILE_DROP', ON_NAV_CLICK = 'ON_NAV_CLICK', } @@ -44,6 +45,7 @@ export default class HapplaBoxViewer { zoomFactor: 1, onAfterZoomChanged: HapplaBoxViewer.onAfterZoomChanged, onMouseWheel: HapplaBoxViewer.onMouseWheel, + onContentSizeChanged: HapplaBoxViewer.onContentSizeChanged, }); _boxEl.addEventListener('dragenter', HapplaBoxViewer.onFileDragEntered); @@ -168,11 +170,23 @@ export default class HapplaBoxViewer { } as IMouseEventArgs, true); } + private static onContentSizeChanged(rect: DOMRect) { + post(Web2FrontendMsgNames.ON_CONTENT_SIZE_CHANGED, { + Dpi: _boxEl.options.scaleRatio, + X: rect.x, + Y: rect.y, + Width: rect.width, + Height: rect.height, + }, true); + } + private static onAfterZoomChanged(e: IZoomEventArgs) { post(Web2FrontendMsgNames.ON_ZOOM_CHANGED, { ZoomFactor: e.zoomFactor, IsManualZoom: e.isManualZoom, IsZoomModeChanged: e.isZoomModeChanged, + X: e.x, + Y: e.y, }, true); } diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBox.ts b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBox.ts index bcda29c80..7d153cb53 100644 --- a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBox.ts +++ b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBox.ts @@ -171,6 +171,10 @@ export class HapplaBox { private async onResizing() { if (this.checkIfNeedRecenter()) { await this.recenter(); + + // raise event onContentSizeChanged + const bound = this.boxContentEl.getBoundingClientRect(); + this.#options.onContentSizeChanged(bound); } this.#options.onResizing(); @@ -557,6 +561,9 @@ export class HapplaBox { .translateSelf(-x, -y) .multiplySelf(this.domMatrix); + this.updateImageRendering(); + await this.applyTransform(options.duration); + // raise event onAfterZoomChanged this.#options.onAfterZoomChanged({ zoomFactor: this.zoomFactor, @@ -566,8 +573,9 @@ export class HapplaBox { isZoomModeChanged: options.isZoomModeChanged || false, }); - this.updateImageRendering(); - await this.applyTransform(options.duration); + // raise event onContentSizeChanged + const bound = this.boxContentEl.getBoundingClientRect(); + this.#options.onContentSizeChanged(bound); } public async applyTransform(duration = 0) { diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBoxTypes.ts b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBoxTypes.ts index 51bff58da..c7a104d2c 100644 --- a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBoxTypes.ts +++ b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBoxTypes.ts @@ -60,6 +60,7 @@ export interface IHapplaBoxOptions { onBeforeContentReady?: () => void; onContentReady?: () => void; + onContentSizeChanged?: (e: DOMRect) => void; onResizing?: () => void; onMouseWheel?: (e: WheelEvent) => void; diff --git a/Source/Components/ImageGlass.Views/Enums.cs b/Source/Components/ImageGlass.Views/Enums.cs index 244b7b214..f6e800a92 100644 --- a/Source/Components/ImageGlass.Views/Enums.cs +++ b/Source/Components/ImageGlass.Views/Enums.cs @@ -138,6 +138,7 @@ public static class Web2FrontendMsgNames public static string ON_ZOOM_CHANGED => "ON_ZOOM_CHANGED"; public static string ON_POINTER_DOWN => "ON_POINTER_DOWN"; public static string ON_MOUSE_WHEEL => "ON_MOUSE_WHEEL"; + public static string ON_CONTENT_SIZE_CHANGED => "ON_CONTENT_SIZE_CHANGED"; public static string ON_FILE_DROP => "ON_FILE_DROP"; public static string ON_NAV_CLICK => "ON_NAV_CLICK"; diff --git a/Source/Components/ImageGlass.Views/ViewerCanvas.cs b/Source/Components/ImageGlass.Views/ViewerCanvas.cs index 59f370774..08410ec9d 100644 --- a/Source/Components/ImageGlass.Views/ViewerCanvas.cs +++ b/Source/Components/ImageGlass.Views/ViewerCanvas.cs @@ -1700,12 +1700,17 @@ protected virtual void DrawCheckerboardLayer(DXGraphics g) if (CheckerboardMode == CheckerboardMode.Image) { - if (UseWebview2) return; - - // no need to draw checkerboard if image does not has alpha pixels - if (!HasAlphaPixels) return; + if (UseWebview2) + { + region = _web2DestRect; + } + else + { + // no need to draw checkerboard if image does not has alpha pixels + if (!HasAlphaPixels) return; - region = _destRect; + region = _destRect; + } } else { diff --git a/Source/Components/ImageGlass.Views/ViewerCanvas_Webview2.cs b/Source/Components/ImageGlass.Views/ViewerCanvas_Webview2.cs index 2fdb75412..5dc22350c 100644 --- a/Source/Components/ImageGlass.Views/ViewerCanvas_Webview2.cs +++ b/Source/Components/ImageGlass.Views/ViewerCanvas_Webview2.cs @@ -35,6 +35,7 @@ public partial class ViewerCanvas private string _web2NavLeftImagePath = string.Empty; private string _web2NavRightImagePath = string.Empty; private MouseEventArgs? _web2PointerDownEventArgs = null; + private RectangleF _web2DestRect = RectangleF.Empty; // Properties @@ -210,6 +211,14 @@ private void Web2_Web2MessageReceived(object? sender, Web2MessageReceivedEventAr var mouseWheelEventArgs = ViewerCanvas.ParseMouseEventJson(e.Data); this.OnMouseWheel(mouseWheelEventArgs); } + else if (e.Name == Web2FrontendMsgNames.ON_CONTENT_SIZE_CHANGED) + { + _web2DestRect = ViewerCanvas.ParseContentSizeChangedEventJson(e.Data); + if (!_web2DestRect.IsEmpty) + { + this.Invalidate(); + } + } else if (e.Name == Web2FrontendMsgNames.ON_FILE_DROP) { var filePaths = e.AdditionalObjects.Where(i => i is CoreWebView2File) @@ -428,20 +437,19 @@ private ZoomEventArgs ParseZoomEventJson(string json) var dict = BHelper.ParseJson(json) .ToDictionary(i => i.Key, i => i.Value.ToString() ?? string.Empty); - if (dict.TryGetValue("ZoomFactor", out var zoomFactor)) + if (dict.TryGetValue(nameof(ZoomEventArgs.ZoomFactor), out var zoomFactor)) { _ = float.TryParse(zoomFactor, out _zoomFactor); } - if (dict.TryGetValue("IsManualZoom", out var isManualZoom)) + if (dict.TryGetValue(nameof(ZoomEventArgs.IsManualZoom), out var isManualZoom)) { _isManualZoom = isManualZoom.Equals("true", StringComparison.InvariantCultureIgnoreCase); } - if (dict.TryGetValue("IsZoomModeChanged", out var zoomModeChanged)) + if (dict.TryGetValue(nameof(ZoomEventArgs.IsZoomModeChange), out var zoomModeChanged)) { isZoomModeChanged = zoomModeChanged.Equals("true", StringComparison.InvariantCultureIgnoreCase); } - return new ZoomEventArgs() { ZoomFactor = _zoomFactor, @@ -453,6 +461,46 @@ private ZoomEventArgs ParseZoomEventJson(string json) } + /// + /// Parses JSON string to . + /// + private static RectangleF ParseContentSizeChangedEventJson(string json) + { + var rect = new RectangleF(); + var dict = BHelper.ParseJson(json) + .ToDictionary(i => i.Key, i => i.Value.ToString() ?? string.Empty); + + // save the dest rect of Web2 + var dpi = DpiApi.DpiScale; + if (dict.TryGetValue("Dpi", out var dpiStr)) + { + _ = float.TryParse(dpiStr, out dpi); + } + if (dict.TryGetValue("X", out var xStr)) + { + _ = float.TryParse(xStr, out var x); + rect.X = x * dpi; + } + if (dict.TryGetValue("Y", out var yStr)) + { + _ = float.TryParse(yStr, out var y); + rect.Y = y * dpi; + } + if (dict.TryGetValue("Width", out var widthStr)) + { + _ = float.TryParse(widthStr, out var width); + rect.Width = width * dpi; + } + if (dict.TryGetValue("Height", out var heightStr)) + { + _ = float.TryParse(heightStr, out var height); + rect.Height = height * dpi; + } + + return rect; + } + + /// /// Parses JSON string to . ///