diff --git a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs index 5b403ff53d..2f248c0d47 100644 --- a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs +++ b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs @@ -4,6 +4,7 @@ using System; using System.Drawing; +using System.IO; using System.IO.Abstractions; using System.Reflection; using System.Runtime.CompilerServices; @@ -96,6 +97,12 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown } } + /// + /// Represent WebView2 user data folder path. + /// + private string _webView2UserDataFolder = System.Environment.GetEnvironmentVariable("USERPROFILE") + + "\\AppData\\LocalLow\\Microsoft\\PowerToys\\MarkdownPreview-Temp"; + /// /// Initializes a new instance of the class. /// @@ -118,6 +125,8 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown /// Path to the file. public override void DoPreview(T dataSource) { + CleanupWebView2UserDataFolder(); + _infoBarDisplayed = false; try @@ -145,21 +154,11 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown Dock = DockStyle.Fill, }; - _browser.NavigationStarting += async (object sender, CoreWebView2NavigationStartingEventArgs args) => - { - if (args.Uri != null && args.IsUserInitiated) - { - args.Cancel = true; - await Launcher.LaunchUriAsync(new Uri(args.Uri)); - } - }; - InvokeOnControlThread(() => { ConfiguredTaskAwaitable.ConfiguredTaskAwaiter webView2EnvironmentAwaiter = CoreWebView2Environment - .CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") + - "\\AppData\\LocalLow\\Microsoft\\PowerToys\\MarkdownPreview-Temp") + .CreateAsync(userDataFolder: _webView2UserDataFolder) .ConfigureAwait(true).GetAwaiter(); webView2EnvironmentAwaiter.OnCompleted(() => { @@ -171,9 +170,34 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true); await _browser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.addEventListener('contextmenu', window => {window.preventDefault();});"); _browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow); - _browser.NavigateToString(markdownHTML); + + // WebView2.NavigateToString() limitation + // See https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatetostring?view=webview2-dotnet-1.0.864.35#remarks + // While testing the limit, it turned out it is ~1.5MB, so to be on a safe side we go for 1.5m bytes + Uri filenameUri = null; + if (markdownHTML.Length > 1_500_000) + { + string filename = _webView2UserDataFolder + "\\" + Guid.NewGuid().ToString() + ".html"; + File.WriteAllText(filename, markdownHTML); + filenameUri = new Uri(filename); + _browser.Source = filenameUri; + } + else + { + _browser.NavigateToString(markdownHTML); + } + Controls.Add(_browser); + _browser.NavigationStarting += async (object sender, CoreWebView2NavigationStartingEventArgs args) => + { + if (args.Uri != null && args.Uri != filenameUri?.ToString() && args.IsUserInitiated) + { + args.Cancel = true; + await Launcher.LaunchUriAsync(new Uri(args.Uri)); + } + }; + if (_infoBarDisplayed) { _infoBar = GetTextBoxControl(Resources.BlockedImageInfoText); @@ -190,9 +214,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown PowerToysTelemetry.Log.WriteEvent(new MarkdownFilePreviewed()); } -#pragma warning disable CA1031 // Do not catch general exception types catch (Exception ex) -#pragma warning restore CA1031 // Do not catch general exception types { PowerToysTelemetry.Log.WriteEvent(new MarkdownFilePreviewError { Message = ex.Message }); @@ -264,5 +286,25 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown { _infoBarDisplayed = true; } + + /// + /// Cleanup the previously created tmp html files from svg files bigger than 2MB. + /// + private void CleanupWebView2UserDataFolder() + { + try + { + // Cleanup temp dir + var dir = new DirectoryInfo(_webView2UserDataFolder); + + foreach (var file in dir.EnumerateFiles("*.html")) + { + file.Delete(); + } + } + catch (Exception) + { + } + } } }