|
5 | 5 | using System.Globalization;
|
6 | 6 | using System.Reflection;
|
7 | 7 | using System.Runtime.CompilerServices;
|
8 |
| -using System.Xml.Linq; |
| 8 | +using System.Threading; |
| 9 | + |
9 | 10 | using Common.Utilities;
|
10 | 11 | using ManagedCommon;
|
11 | 12 | using Microsoft.Web.WebView2.Core;
|
@@ -117,151 +118,92 @@ public Bitmap GetThumbnailImpl(uint cx)
|
117 | 118 | _browser.Height = (int)cx;
|
118 | 119 | _browser.NavigationCompleted += async (object sender, CoreWebView2NavigationCompletedEventArgs args) =>
|
119 | 120 | {
|
120 |
| - try |
| 121 | + var a = await _browser.ExecuteScriptAsync($"document.getElementsByTagName('svg')[0].viewBox;"); |
| 122 | + if (a != null) |
121 | 123 | {
|
122 |
| - // Check if the SVG element is present |
123 |
| - var a = await _browser.ExecuteScriptAsync($"document.getElementsByTagName('svg')[0].viewBox;"); |
124 |
| - if (a != null) |
125 |
| - { |
126 |
| - var svgContent = SvgContents.Substring(SvgContents.IndexOf("<svg", StringComparison.OrdinalIgnoreCase), SvgContents.IndexOf("</svg>", StringComparison.OrdinalIgnoreCase) - SvgContents.IndexOf("<svg", StringComparison.OrdinalIgnoreCase) + "</svg>".Length); |
127 |
| - |
128 |
| - Dictionary<string, string> styleDict = new Dictionary<string, string>(); |
129 |
| - |
130 |
| - // Try to parse the SVG content |
131 |
| - try |
132 |
| - { |
133 |
| - // Attempt to parse the svgContent |
134 |
| - var svgDocument = XDocument.Parse(svgContent); |
135 |
| - var svgElement = svgDocument.Root; |
136 |
| - var currentStyle = svgElement?.Attribute("style")?.Value; |
137 |
| - |
138 |
| - // If style attribute exists, preserve existing styles |
139 |
| - if (!string.IsNullOrEmpty(currentStyle) && currentStyle != "null") |
140 |
| - { |
141 |
| - styleDict = currentStyle |
142 |
| - .Split(';', StringSplitOptions.RemoveEmptyEntries) |
143 |
| - .Select(stylePart => stylePart.Split(':', 2, StringSplitOptions.TrimEntries)) |
144 |
| - .Where(styleKeyValue => styleKeyValue.Length == 2 && !string.IsNullOrEmpty(styleKeyValue[0])) |
145 |
| - .ToDictionary( |
146 |
| - styleKeyValue => styleKeyValue[0], |
147 |
| - styleKeyValue => styleKeyValue[1]); |
148 |
| - } |
149 |
| - } |
150 |
| - catch (Exception ex) |
151 |
| - { |
152 |
| - // Log the error if the SVG content is not valid or parsing fails |
153 |
| - Logger.LogError($"Failed to parse SVG content: {ex.Message}"); |
154 |
| - } |
155 |
| - |
156 |
| - // Add or replace width and height in the existing style |
157 |
| - styleDict["width"] = "100%"; |
158 |
| - styleDict["height"] = "100%"; |
159 |
| - |
160 |
| - // Construct a single JavaScript string to set all properties |
161 |
| - var styleScript = string.Join(";", styleDict.Select(kv => $"document.getElementsByTagName('svg')[0].style.setProperty('{kv.Key}', '{kv.Value}');")); |
162 |
| - |
163 |
| - // Apply the new style attributes using the constructed script |
164 |
| - await _browser.ExecuteScriptAsync(styleScript); |
165 |
| - } |
166 |
| - |
167 |
| - // Hide scrollbar - fixes #18286 |
168 |
| - await _browser.ExecuteScriptAsync("document.querySelector('body').style.overflow='hidden'"); |
| 124 | + await _browser.ExecuteScriptAsync($"document.getElementsByTagName('svg')[0].style = 'width:100%;height:100%';"); |
| 125 | + } |
169 | 126 |
|
170 |
| - MemoryStream ms = new MemoryStream(); |
171 |
| - await _browser.CoreWebView2.CapturePreviewAsync(CoreWebView2CapturePreviewImageFormat.Png, ms); |
172 |
| - thumbnail = new Bitmap(ms); |
| 127 | + // Hide scrollbar - fixes #18286 |
| 128 | + await _browser.ExecuteScriptAsync("document.querySelector('body').style.overflow='hidden'"); |
173 | 129 |
|
174 |
| - if (thumbnail.Width != cx && thumbnail.Height != cx && thumbnail.Width != 0 && thumbnail.Height != 0) |
175 |
| - { |
176 |
| - // We are not the appropriate size for caller. Resize now while |
177 |
| - // respecting the aspect ratio. |
178 |
| - float scale = Math.Min((float)cx / thumbnail.Width, (float)cx / thumbnail.Height); |
179 |
| - int scaleWidth = (int)(thumbnail.Width * scale); |
180 |
| - int scaleHeight = (int)(thumbnail.Height * scale); |
181 |
| - thumbnail = ResizeImage(thumbnail, scaleWidth, scaleHeight); |
182 |
| - } |
| 130 | + MemoryStream ms = new MemoryStream(); |
| 131 | + await _browser.CoreWebView2.CapturePreviewAsync(CoreWebView2CapturePreviewImageFormat.Png, ms); |
| 132 | + thumbnail = new Bitmap(ms); |
183 | 133 |
|
184 |
| - thumbnailDone.Set(); |
185 |
| - } |
186 |
| - catch (Exception ex) |
| 134 | + if (thumbnail.Width != cx && thumbnail.Height != cx && thumbnail.Width != 0 && thumbnail.Height != 0) |
187 | 135 | {
|
188 |
| - Logger.LogError("Error during NavigationCompleted: ", ex); |
189 |
| - thumbnailDone.Set(); |
| 136 | + // We are not the appropriate size for caller. Resize now while |
| 137 | + // respecting the aspect ratio. |
| 138 | + float scale = Math.Min((float)cx / thumbnail.Width, (float)cx / thumbnail.Height); |
| 139 | + int scaleWidth = (int)(thumbnail.Width * scale); |
| 140 | + int scaleHeight = (int)(thumbnail.Height * scale); |
| 141 | + thumbnail = ResizeImage(thumbnail, scaleWidth, scaleHeight); |
190 | 142 | }
|
| 143 | + |
| 144 | + thumbnailDone.Set(); |
191 | 145 | };
|
192 | 146 |
|
193 | 147 | var webView2Options = new CoreWebView2EnvironmentOptions("--block-new-web-contents");
|
194 | 148 | ConfiguredTaskAwaitable<CoreWebView2Environment>.ConfiguredTaskAwaiter
|
195 |
| - webView2EnvironmentAwaiter = CoreWebView2Environment |
196 |
| - .CreateAsync(userDataFolder: _webView2UserDataFolder, options: webView2Options) |
197 |
| - .ConfigureAwait(true).GetAwaiter(); |
| 149 | + webView2EnvironmentAwaiter = CoreWebView2Environment |
| 150 | + .CreateAsync(userDataFolder: _webView2UserDataFolder, options: webView2Options) |
| 151 | + .ConfigureAwait(true).GetAwaiter(); |
198 | 152 |
|
199 | 153 | webView2EnvironmentAwaiter.OnCompleted(async () =>
|
200 | 154 | {
|
201 |
| - for (int attempt = 0; attempt < 3; attempt++) |
| 155 | + try |
202 | 156 | {
|
203 |
| - try |
| 157 | + _webView2Environment = webView2EnvironmentAwaiter.GetResult(); |
| 158 | + await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true); |
| 159 | + _browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Deny); |
| 160 | + _browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false; |
| 161 | + _browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false; |
| 162 | + _browser.CoreWebView2.Settings.AreDevToolsEnabled = false; |
| 163 | + _browser.CoreWebView2.Settings.AreHostObjectsAllowed = false; |
| 164 | + _browser.CoreWebView2.Settings.IsGeneralAutofillEnabled = false; |
| 165 | + _browser.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false; |
| 166 | + _browser.CoreWebView2.Settings.IsScriptEnabled = false; |
| 167 | + _browser.CoreWebView2.Settings.IsWebMessageEnabled = false; |
| 168 | + |
| 169 | + // Don't load any resources. |
| 170 | + _browser.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All); |
| 171 | + _browser.CoreWebView2.WebResourceRequested += (object sender, CoreWebView2WebResourceRequestedEventArgs e) => |
204 | 172 | {
|
205 |
| - _webView2Environment = webView2EnvironmentAwaiter.GetResult(); |
206 |
| - await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true); |
207 |
| - _browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Deny); |
208 |
| - _browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false; |
209 |
| - _browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false; |
210 |
| - _browser.CoreWebView2.Settings.AreDevToolsEnabled = false; |
211 |
| - _browser.CoreWebView2.Settings.AreHostObjectsAllowed = false; |
212 |
| - _browser.CoreWebView2.Settings.IsGeneralAutofillEnabled = false; |
213 |
| - _browser.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false; |
214 |
| - _browser.CoreWebView2.Settings.IsScriptEnabled = false; |
215 |
| - _browser.CoreWebView2.Settings.IsWebMessageEnabled = false; |
216 |
| - |
217 |
| - // Don't load any resources. |
218 |
| - _browser.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All); |
219 |
| - _browser.CoreWebView2.WebResourceRequested += (object sender, CoreWebView2WebResourceRequestedEventArgs e) => |
220 |
| - { |
221 |
| - // Show local file we've saved with the svg contents. Block all else. |
222 |
| - if (new Uri(e.Request.Uri) != _localFileURI) |
223 |
| - { |
224 |
| - e.Response = _browser.CoreWebView2.Environment.CreateWebResourceResponse(null, 403, "Forbidden", null); |
225 |
| - } |
226 |
| - }; |
227 |
| - |
228 |
| - // WebView2.NavigateToString() limitation |
229 |
| - // See https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatetostring?view=webview2-dotnet-1.0.864.35#remarks |
230 |
| - // While testing the limit, it turned out it is ~1.5MB, so to be on a safe side we go for 1.5m bytes |
231 |
| - SvgContentsReady.Wait(); |
232 |
| - if (string.IsNullOrEmpty(SvgContents) || !SvgContents.Contains("svg")) |
| 173 | + // Show local file we've saved with the svg contents. Block all else. |
| 174 | + if (new Uri(e.Request.Uri) != _localFileURI) |
233 | 175 | {
|
234 |
| - thumbnailDone.Set(); |
235 |
| - return; |
| 176 | + e.Response = _browser.CoreWebView2.Environment.CreateWebResourceResponse(null, 403, "Forbidden", null); |
236 | 177 | }
|
| 178 | + }; |
237 | 179 |
|
238 |
| - if (SvgContents.Length > 1_500_000) |
239 |
| - { |
240 |
| - string filename = _webView2UserDataFolder + "\\" + Guid.NewGuid().ToString() + ".html"; |
241 |
| - File.WriteAllText(filename, SvgContents); |
242 |
| - _localFileURI = new Uri(filename); |
243 |
| - _browser.Source = _localFileURI; |
244 |
| - } |
245 |
| - else |
246 |
| - { |
247 |
| - _browser.NavigateToString(SvgContents); |
248 |
| - } |
| 180 | + // WebView2.NavigateToString() limitation |
| 181 | + // See https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatetostring?view=webview2-dotnet-1.0.864.35#remarks |
| 182 | + // While testing the limit, it turned out it is ~1.5MB, so to be on a safe side we go for 1.5m bytes |
| 183 | + SvgContentsReady.Wait(); |
| 184 | + if (string.IsNullOrEmpty(SvgContents) || !SvgContents.Contains("svg")) |
| 185 | + { |
| 186 | + thumbnailDone.Set(); |
| 187 | + return; |
| 188 | + } |
249 | 189 |
|
250 |
| - break; // Exit the retry loop if initialization succeeds |
| 190 | + if (SvgContents.Length > 1_500_000) |
| 191 | + { |
| 192 | + string filename = _webView2UserDataFolder + "\\" + Guid.NewGuid().ToString() + ".html"; |
| 193 | + File.WriteAllText(filename, SvgContents); |
| 194 | + _localFileURI = new Uri(filename); |
| 195 | + _browser.Source = _localFileURI; |
251 | 196 | }
|
252 |
| - catch (Exception ex) |
| 197 | + else |
253 | 198 | {
|
254 |
| - Logger.LogError($"Initialization attempt {attempt} failed: {ex.Message}"); |
255 |
| - if (attempt == 2) |
256 |
| - { |
257 |
| - Logger.LogError($"Failed running webView2Environment completed for {FilePath} : ", ex); |
258 |
| - thumbnailDone.Set(); |
259 |
| - return; |
260 |
| - } |
261 |
| - |
262 |
| - await Task.Delay(1000); // Delay before retrying |
| 199 | + _browser.NavigateToString(SvgContents); |
263 | 200 | }
|
264 | 201 | }
|
| 202 | + catch (Exception ex) |
| 203 | + { |
| 204 | + Logger.LogError($"Failed running webView2Environment completed for {FilePath} : ", ex); |
| 205 | + thumbnailDone.Set(); |
| 206 | + } |
265 | 207 | });
|
266 | 208 |
|
267 | 209 | while (!thumbnailDone.Wait(75))
|
|
0 commit comments