From 78b4c7db855a2daee98e830613a3f331ba89395e Mon Sep 17 00:00:00 2001 From: dcog989 Date: Mon, 14 Jul 2025 00:43:39 +0100 Subject: [PATCH 1/2] Fix BrowserBookmark '100% CPU' issue # Fix BrowserBookmark plugin locking threads at 100% CPU The following files were modified to implement this fix: 1. /Flow.Launcher.Plugin.BrowserBookmark.csproj - packages SkiaSharp and Svg.Skia added to output WEBP 2. /Helper/FaviconHelper.cs - new method, TryConvertToWebp, added to take any image data and encode to WEBP 3. /FirefoxBookmarkLoader.cs - LoadFaviconsFromDb to use the new helper which ensures only safe WEBP files are used by the UI, which resolves the CPU-locking. It was GZIPped SVGs that were causing the thread / CPU lock. --- .../FirefoxBookmarkLoader.cs | 48 +++++++------- ...low.Launcher.Plugin.BrowserBookmark.csproj | 2 + .../Helper/FaviconHelper.cs | 62 ++++++++++++++++--- 3 files changed, 82 insertions(+), 30 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index ec3b867ea81..f933fa2bb76 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Threading.Tasks; using Flow.Launcher.Plugin.BrowserBookmark.Helper; @@ -134,10 +135,6 @@ private void LoadFaviconsFromDb(string dbPath, List bookmarks) try { - if (string.IsNullOrEmpty(bookmark.Url)) - return; - - // Extract domain from URL if (!Uri.TryCreate(bookmark.Url, UriKind.Absolute, out Uri uri)) return; @@ -146,43 +143,48 @@ private void LoadFaviconsFromDb(string dbPath, List bookmarks) // Query for latest Firefox version favicon structure using var cmd = connection.CreateCommand(); cmd.CommandText = @" - SELECT i.data + SELECT i.id, i.data FROM moz_icons i JOIN moz_icons_to_pages ip ON i.id = ip.icon_id JOIN moz_pages_w_icons p ON ip.page_id = p.id - WHERE p.page_url LIKE @url - AND i.data IS NOT NULL - ORDER BY i.width DESC -- Select largest icon available + WHERE p.page_url LIKE @domain + ORDER BY i.width DESC LIMIT 1"; - cmd.Parameters.AddWithValue("@url", $"%{domain}%"); + cmd.Parameters.AddWithValue("@domain", $"%{domain}%"); using var reader = cmd.ExecuteReader(); - if (!reader.Read() || reader.IsDBNull(0)) + if (!reader.Read() || reader.IsDBNull(1)) return; + var iconId = reader.GetInt64(0).ToString(); var imageData = (byte[])reader["data"]; if (imageData is not { Length: > 0 }) return; - - string faviconPath; - if (FaviconHelper.IsSvgData(imageData)) + + if (imageData.Length > 2 && imageData[0] == 0x1f && imageData[1] == 0x8b) { - faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}.svg"); + using var inputStream = new MemoryStream(imageData); + using var gZipStream = new GZipStream(inputStream, CompressionMode.Decompress); + using var outputStream = new MemoryStream(); + gZipStream.CopyTo(outputStream); + imageData = outputStream.ToArray(); } - else + + var webpData = FaviconHelper.TryConvertToWebp(imageData); + + if (webpData != null) { - faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}.png"); - } + var faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}_{iconId}.webp"); - // Filter out duplicate favicons - if (savedPaths.TryAdd(faviconPath, true)) - { - FaviconHelper.SaveBitmapData(imageData, faviconPath); - } + if (savedPaths.TryAdd(faviconPath, true)) + { + FaviconHelper.SaveBitmapData(webpData, faviconPath); + } - bookmark.FaviconPath = faviconPath; + bookmark.FaviconPath = faviconPath; + } } catch (Exception ex) { diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj index 3fb0fa46f64..7b2fb47f843 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -97,6 +97,8 @@ + + diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs index a879dcefd1b..bd8492408da 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using SkiaSharp; +using Svg.Skia; namespace Flow.Launcher.Plugin.BrowserBookmark.Helper; @@ -65,12 +67,58 @@ public static void SaveBitmapData(byte[] imageData, string outputPath) } } - public static bool IsSvgData(byte[] data) + public static byte[] TryConvertToWebp(byte[] data) { - if (data.Length < 5) - return false; - string start = System.Text.Encoding.ASCII.GetString(data, 0, Math.Min(100, data.Length)); - return start.Contains(" Date: Mon, 14 Jul 2025 09:01:59 +0800 Subject: [PATCH 2/2] Add code comments --- .../FirefoxBookmarkLoader.cs | 7 ++++--- .../Helper/FaviconHelper.cs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index f933fa2bb76..ef029809a19 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -162,7 +162,8 @@ ORDER BY i.width DESC if (imageData is not { Length: > 0 }) return; - + + // Check if the image data is compressed (GZip) if (imageData.Length > 2 && imageData[0] == 0x1f && imageData[1] == 0x8b) { using var inputStream = new MemoryStream(imageData); @@ -171,9 +172,9 @@ ORDER BY i.width DESC gZipStream.CopyTo(outputStream); imageData = outputStream.ToArray(); } - + + // Convert the image data to WebP format var webpData = FaviconHelper.TryConvertToWebp(imageData); - if (webpData != null) { var faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}_{iconId}.webp"); diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs index bd8492408da..72cb15b3396 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs @@ -121,4 +121,4 @@ public static byte[] TryConvertToWebp(byte[] data) return null; } -} \ No newline at end of file +}