Repository navigation
feat(mobile): draw SVG files and pinch-zoom every image preview, Android included - #36608
Conversation
253a192 to
1b0fd60
Compare
6850f56 to
2b49018
Compare
af9ef0b to
8781d6b
Compare
8781d6b to
fa81c08
Compare
21e0395 to
db1c4f7
Compare
fa81c08 to
f063e17
Compare
…g and double-tap to zoom images
…e SVG artifacts get a preview
f063e17 to
3a0d75a
Compare
|
No actionable comments were generated in the recent review.
|
ELI5
On the phone,
.svgfiles now show the drawing instead of a wall of XML, with a Preview | Source toggle to get the XML back. Every image preview on the phone can now be pinched, dragged and double-tapped to zoom — including on Android, where image zoom never worked.What Changed
SVG on mobile (mobile half of #23629)
mobile-artifact-kind.tssent.svgdown the text path on purpose, so the file preview and mirrored file tabs showed XML source..svgis a newvectorartifact kind. It is still read as text (files.read), and the same reply feeds a drawing and the existing syntax-highlighted Source view (MobileSvgPreview). The drawing is sized from the SVG's ownwidth/height/viewBoxusing the samereadSvgIntrinsicSizedesktop uses, so "fit" and "100%" agree across apps. Fit enlarges vectors to fill the screen.too, instead of rejecting it as an unsupported image.<img>data URI, so its scripts never run and its external references are never fetched. The shipped shell CSP already allowsimg-src data:.Pan/zoom on mobile (all images)
<ScrollView maximumZoomScale>— iOS-only props, so Android had no zoom at all, and the box was sized from the screen rather than the file.MobilePanZoomImageuses pointer events withtouch-action: noneon the web page: two-finger pinch zooms at the fingers, one finger drags, double-tap toggles fit ↔ actual size (or 2.5× when actual size is about the same as fit). Panning stops at the image's edges, and rotating the phone while zoomed keeps the image against them. The content under the fingers stays under them while a pinch moves.pan-zoom-view.tsmoved fromsrc/renderer/.../editor/tosrc/shared/, unchanged except that its three constants moved with it.MobileHtmlPreview's Preview/Source tabs were extracted toMobilePreviewSourceTabsand reused.Compatibility
.svgas UTF-8 text fromfiles.read(readLocalMobileFile), so older desktops and SSH hosts work.Linked Issue
Fixes #23629 (with #36576 for the desktop half)
Visual Proof
iOS 26 simulator (iPhone, real WKWebView in the Orca dev client, paired to a host built from this branch). The pinch gestures are real two-finger touches.
wide.svg(viewBox only) fitted, then pinched (the vector stays sharp and the page chrome does not zoom):Zoomed and dragged right: the image pans to its left edge and stops there.
A 1600 × 900 PNG pinched, then the phone rotated while zoomed: the image still fills the screen.
Headless Chromium with touch (the render test), as an Android WebView stand-in:
Mobile web bundle under the shipped shell CSP, 390 × 844 with touch, rendering a
viewBox-only SVG (1200 × 240). Fitted to the phone's width (the browser alone would draw it at 300 px):After a two-finger pinch:
Before: the same file showed as XML source (the behavior described in #23629).
Testing
New render test
mobile-web-app-svg-preview-render.test.mjsbuilds the real mobile web bundle, serves it with the shipped CSP, and in headless Chromium with touch: checks the drawing loads at 5:1 and fills the width, pinches with two CDP touch points (width more than doubles), double-taps back to fit, and flips to Source. It produced the screenshots above.mobile-markdown-image-source.test.ts: an SVG image in markdown is read withfiles.readand drawn as an SVG data URI.mobile-artifact-kind.test.tsupdated for thevectorkind.Mobile
typecheckand the full mobile suite pass (12,000 tests). The only two failures,native-document-bundle.test.ts, are in terminal code this PR doesn't touch; CI decides. Desktoptc:weband the movedpan-zoom-viewtests pass.New strings are translated into all 10 mobile locales.
iOS 26 simulator, real app. I built the dev client for this branch and served the web bundle from a headless host built from this branch, then paired the two. On
.svgand.pngI checked fit, real two-finger pinch, one-finger pan with edge stops, double-tap back to fit, the Source tab, rotation while zoomed, and an SVG image inside Markdown.Cross-reviewed twice with Codex (GPT 6.1 Sol, xhigh). Fixed from that review: pinch drift when the fingers move, blank space after rotating while panned, missing Preview on writable SVG artifacts, and a save error hidden in Preview. Regression tests cover the pinch and rotation math.
Known, not from this PR: on iOS 26, a long rightward drag anywhere in a web-shell page triggers the system's full-screen back swipe. That pops the host screen, even on a Markdown file with no zoom. A zoomed image therefore pans right only until iOS takes the gesture. Fixing it needs a shell change to the nested stack's swipe handling, which would also change Back for every page with in-page history, so it is left for a separate PR.
Not tested: a physical phone and an Android emulator (none installed). Headless Chromium covers Chromium's touch pipeline.
I manually tested these changes locally
Automated tests added/updated, or explained why not below