From 7938034d85121ca130d2059eb2d540d5475ac4cb Mon Sep 17 00:00:00 2001 From: Yusuf Suleman Date: Sat, 4 Apr 2026 00:30:37 -0500 Subject: [PATCH] perf: lazy async image decoding + max-height to prevent scroll freeze MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ROOT CAUSE: Articles from sites like onemileatatime.com serve WebP images with .jpeg extensions. WebKit attempts JPEG decode, fails, retries as WebP — the retry loop blocks the compositor thread during scroll, causing ~1s freezes per image. FIX 1 — Image attributes (ArticleHTMLBuilder.optimizeImages): Regex injects loading="lazy" decoding="async" on all tags that don't already have loading= set. This tells WebKit to: - decode images off the main/compositor thread (decoding=async) - only decode when approaching viewport (loading=lazy) FIX 2 — CSS max-height: img { max-height: 600px; object-fit: contain; } Limits decoded image buffer size. A 1200x900 image still displays at full width but WebKit doesn't need to composite oversized tiles. Both fixes are content-rendering optimizations only — no changes to WKWebView architecture, scrolling model, or layout system. Also marked Atmos Rewards articles as unread for testing. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Features/Reader/Views/ArticleView.swift | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/ios/Platform/Platform/Features/Reader/Views/ArticleView.swift b/ios/Platform/Platform/Features/Reader/Views/ArticleView.swift index aab286c..5400642 100644 --- a/ios/Platform/Platform/Features/Reader/Views/ArticleView.swift +++ b/ios/Platform/Platform/Features/Reader/Views/ArticleView.swift @@ -156,7 +156,7 @@ enum ArticleHTMLBuilder { .article-meta { font-size: 13px; color: #8B6914; line-height: 1.4; } - img { max-width: 100%; height: auto; border-radius: 8px; margin: 12px 0; } + img { max-width: 100%; height: auto; max-height: 600px; object-fit: contain; border-radius: 8px; margin: 12px 0; } a { color: #8B6914; } h1, h2, h3, h4 { line-height: 1.3; margin-top: 24px; margin-bottom: 8px; } pre, code { background: #f5f0e8; border-radius: 6px; padding: 2px 6px; font-size: 15px; overflow-x: auto; } @@ -214,9 +214,27 @@ enum ArticleHTMLBuilder {

\(titleHTML)

-
\(body)
+
\(optimizeImages(body))
""" } + + /// Add loading="lazy" and decoding="async" to all tags. + /// This tells WebKit to decode images off the main thread and + /// only when they approach the viewport, preventing scroll freezes + /// from large/mismatched-type images (e.g. WebP served as .jpeg). + private static let imgTagRegex = try! NSRegularExpression( + pattern: #"]*loading=)([^>]*)>"#, + options: .caseInsensitive + ) + + private static func optimizeImages(_ html: String) -> String { + let range = NSRange(html.startIndex..., in: html) + return imgTagRegex.stringByReplacingMatches( + in: html, + range: range, + withTemplate: #""# + ) + } }