This release includes breaking changes for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
Topics
+9 more
Summary
AI summaryBroad release touches Known limitations carried forward, CSS correctness, Verified on hardware, and Image / memory hygiene.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Feature | Medium |
CSS Grid V2 alignment consumes libcss accessors for justify‑content and align‑content. CSS Grid V2 alignment consumes libcss accessors for justify‑content and align‑content. Source: llm_adapter@2026-05-29 Confidence: high |
— |
| Feature | Medium |
CSS budget capped at 384 KB per page; excess sheets are truncated. CSS budget capped at 384 KB per page; excess sheets are truncated. Source: llm_adapter@2026-05-29 Confidence: high |
— |
| Feature | Medium |
Heavy‑site diagnostic line now shows `blocker=` and `css_total=` fields. Heavy‑site diagnostic line now shows `blocker=` and `css_total=` fields. Source: llm_adapter@2026-05-29 Confidence: high |
— |
| Feature | Medium |
Multicol balancing uses bisection to compute optimal target height for `column-fill: balance`. Multicol balancing uses bisection to compute optimal target height for `column-fill: balance`. Source: llm_adapter@2026-05-29 Confidence: high |
— |
| Bugfix | Medium |
`var()` now resolves element's own inline custom properties. `var()` now resolves element's own inline custom properties. Source: llm_adapter@2026-05-29 Confidence: high |
— |
| Bugfix | Medium |
Doc-global table aggregates inline custom properties for cross‑element var() resolution. Doc-global table aggregates inline custom properties for cross‑element var() resolution. Source: llm_adapter@2026-05-29 Confidence: high |
— |
| Bugfix | Medium |
`background-image: linear-gradient(...)` rewritten to reach gradient paint path. `background-image: linear-gradient(...)` rewritten to reach gradient paint path. Source: llm_adapter@2026-05-29 Confidence: high |
— |
| Bugfix | Medium |
Direct image URL navigation scales images to fit the 16 MB per‑image cap while preserving aspect ratio. Direct image URL navigation scales images to fit the 16 MB per‑image cap while preserving aspect ratio. Source: llm_adapter@2026-05-29 Confidence: high |
— |
| Bugfix | Medium |
Decoded‑image cache purged on top‑level navigation, freeing memory headroom. Decoded‑image cache purged on top‑level navigation, freeing memory headroom. Source: llm_adapter@2026-05-29 Confidence: high |
— |
| Bugfix | Medium |
Images outside the redraw clip are lazily decoded only when scrolled into view. Images outside the redraw clip are lazily decoded only when scrolled into view. Source: llm_adapter@2026-05-29 Confidence: high |
— |
Full changelog
MacSurf 0.7 — Cleanup
Released: 2026-05-26
Codename: Cleanup
Engine HEAD: fixes271b
Verified on: Power Macintosh G3 iMac, Mac OS 9.1
The headline
Twelve issues closed in a single day. v0.7 is the "resolve all known issues" sprint — a focused correctness + cleanup round on top of v0.6.2's speed work. Nine commits (fixes264 → fixes271b) cleared the entire open-issues backlog on mplsllc/macsurf. Author CSS now reaches more paint paths, image-heavy navigation stays memory-clean, CSS Grid honors author alignment intent, and a long-standing struct-naming workaround got resolved at the root.
Two things stand out from the round:
- Element-scoped
var()resolution. Author CSS like.header { background-image: var(--tile) }now resolves correctly when--tileis defined inline on a different element'sstyle="..."attribute. Mactrove's--header-tilerandom-header pattern just works. - CSS Grid V2 alignment with zero libcss surgery. The previous attempt (fixes159) had failed in nine rounds trying to add a new vendor property; turned out libcss already had public accessors for
justify-content,align-content,align-items,align-self— just had to consume them.
What landed (by area)
CSS correctness
- fixes264 —
var()resolves element's own inline--custom-prop. Threads the cascading element'sinline_stylesheet throughlookup_var()as highest-priority source. Works for the same-element case (element defines and uses the var). - fixes267 — Doc-global inline-extras custom-property table. Aggregates
custom_propertiesfrom everystyle="..."attribute parsed bynscss_create_inline_styleinto a doc-global table consulted bylookup_var(). Covers the cross-element case (parent defines, child uses). Cleared perhtml_createso per-page state doesn't bleed. Pragmatic V1 — last-writer-wins for name collisions, which covers mactrove's single---header-tile-element pattern. - fixes266 —
background-image: linear-gradient(...)rewrite. New cssh_css preprocessor pass renamesbackground-image:to-macsurf-gradient:when the value's first non-whitespace token islinear-gradient(orradial-gradient(. Author CSS using standard CSS3 syntax now reaches the existing vendor gradient paint path. Stacked layered backgrounds still drop on the trailing comma (no regression). Wired into both external sheets and inline-style attributes. - fixes270 — CSS Grid V2 alignment.
layout_gridconsumescss_computed_justify_content(inline-axis track distribution: flex-end, center, space-between, space-around, space-evenly) andcss_computed_align_content(block-axis distribution when there's a definite container height). Discovery that closed the prior 9-round fixes159 stall: libcss already exposed these accessors — no new vendor property needed. fixes270a preserves the CSS-declared container height through the redistribution so the box paints at full declared size instead of shrinking back to natural content height.align-items/align-selfhad already shipped at fixes178d;justify-items/justify-selfdeferred (libcss does not expose those accessors).
Image / memory hygiene
- fixes265 — Direct image URL navigation scale-fit-to-cap. Typing a large image URL (e.g.
https://example.com/photo.jpg) in the address bar pre-fix rendered blank because browser_window passed natural dimensions (4000×3000 → 48 MB RGBA, exceeds the 16 MB per-image ceiling). Pre-clampsdst_w/dst_hproportionally inmacos9_qt_image_redrawbefore the cap-check, preserving aspect ratio. Integer-only math (CW8 PPClong longis unsafe per the well-documented gotcha). - fixes268 #10 — Decoded-image purge on top-level nav. New
macos9_purge_decoded_images()evicts the QT-deferred LRU and zeroesmacsurf__decoded_img_bytes_current. Called frombrowser_window_content_readyafterhlcache_handle_releaseof the old current_content;llcache_clean(true)purges the low-level cache alongside. Heavy-page → heavy-page navigation now starts with fresh budget headroom. Verified on hardware asimg purge: evicted=1769472 remaining=0on a real nav. - fixes269 #8 — Above-fold lazy decode.
macos9_qt_image_redrawnow early-returns when the image's destination rect lies entirely outside the redraw clip. NetSurf core's box-tree walker prunes most below-fold boxes but occasionally invokes redraw on parents whose bbox intersects the clip while specific children don't. Below-fold images stay undecoded until the user scrolls into them; scroll fires a new redraw with a different clip that triggers the decode.
Diagnostic visibility
- fixes268 #9 — Total CSS budget by importance. New 384 KB cumulative cap on CSS bytes per page in
nscss_process_data. Sheets arriving after the cap is hit short-circuit immediately (document order wins — site's main stylesheet processes fully, vendor tail sheets get truncated).macsurf__site_css_total_bytesreset per page inhtml_create. - fixes268 #11 — Heavy mode +
blocker=field. SITE diagnostic line now emitsheavy=N blocker=NAME(none / img_budget / css_budget / fetch_slots / fonts) andcss_total=N/cap.heavy=1latches when any skip counter is non-zero; blocker name picked by priority order. Visible at everyhtml_reformatcompletion. - fixes268a — SITE line unsilencer. fixes253 had silenced
SITE url=...lines by default as a log-noise reduction. v0.7 requires the SITE line forcss_total=andblocker=verification per the issue acceptance criteria, so SITE is back to firing per reformat. Low volume — survivable.
Multicol
- fixes268 #17 — Multicol balancing via bisection.
layout_multicol_inner's per-segmenttarget_heightnow goes through a newmulticol_compute_target_height()helper:column-fill: autouses the viewport height as target (was identical to balance pre-fix;autowas unimplemented).column-fill: balancestarts withmax(tallest, ceil(total/count))heuristic, then bisects downward (6 iterations, 8px convergence) to the smallest target that still fits incountcolumns. Tighter, more visually balanced output for non-uniform item heights.
Build cleanup
- fixes271b —
box_multicol_datarename + Linux/Mac box.h alignment. The_nssuffix onstruct box_multicol_seg_nsandstruct box_multicol_dat_nswas a fixes199h workaround for a CW8 redefinition error. Root cause turned out to be that the Mac'sbox.hhad been carrying these struct definitions plus amulticol_datafield onstruct boxsince fixes199h, while the Linuxbox.hhad neither. Aligned: added the structs + field to Linux'sbox.h, removed the duplicates fromlayout_internal.h, restored standard names (box_multicol_segment,box_multicol_data) inlayout.c. Source trees now match across platforms; single source of truth inbox.h.
Issues closed (12)
All on mplsllc/macsurf:
| # | Title | Resolution |
| --- | --- | --- |
| #2 | Image memory pressure on modern image-heavy pages | fixes268 #10 (purge on nav) + existing fixes161b/162/259/265 deferred-decode |
| #3 | %u specifier in macsurf_debug_log_writef calls | Audit found no remaining hits; already resolved |
| #4 | CSS Grid V2 alignment | fixes270 / fixes270a |
| #5 | Wheel-mouse scroll can crash | Not reproducible on user's hardware; fixes140/141 defensive disable remains effective |
| #8 | Lazy image decode + above-the-fold bias | fixes269 |
| #9 | Total CSS budget by importance | fixes268 |
| #10 | Purge memory cache + decoded-image budget on top-level navigation | fixes268 |
| #11 | Heavy-site mode + blocker= field in SITE diagnostic line | fixes268 |
| #12 | fixes161 memory sweep umbrella | All constituent issues shipped |
| #17 | Multicol V2 — Balancing | fixes268 |
| #18 | Header Audit & Build Cleanup (Struct Renaming) | fixes271b |
| #22 | var() referencing parent's inline --custom-prop drops | fixes267 |
Plus #23 (background-image gradient drops) and #24 (direct image URL blank) filed and closed for the early-session work (fixes266, fixes265).
Verified on hardware
- test.html — fixes264/266/267 probes: purple cross-element
var()block + four gradient blocks (vertical 2-stop, horizontal 2-stop, vertical 3-stop, radial). All paint correctly post-fixes267. - test2.html — fixes268 probes: M1 multicol balance with mixed heights + M2 column-fill: auto in 200px container. Plus fixes267/266 regression checks.
- test3.html — fixes270 probes GA1–GA7: justify-content (center, flex-end, space-between, space-around, space-evenly), align-content: center (200px container, fixes270a confirmation), align-items: flex-end regression check. All seven probes render correctly.
- MacSurf Debug.log confirms fixes268 SITE line:
heavy=0 blocker=none ... css_total=N/393216 ...per reformat,img purge: evicted=N remaining=0on real navigation events.
Known limitations carried forward
justify-items/justify-self(cell horizontal alignment on grids) — libcss in this vintage does not exposecss_computed_justify_items/css_computed_justify_self. Either libcss surgery (the trap zone — see project memory) or atext-alignworkaround would close the gap. Lower priority since container-level distribution (V1 shipped) covers most layouts.- Stacked
background-image: linear-gradient(...), linear-gradient(...)— single-gradient case works; multi-layer parser fails on the trailing comma. Same as pre-fix behaviour, no regression. - TLS fingerprint blocks (Google / Facebook) — carried from v0.6.x; needs ALPN extension support in macTLS or a TLS 1.3 swap. The persistent dead-host list makes them fast-fail.
gap: A Btwo-value form — single value works (97% of cases), two-value collapses tocolumn-gap=B. Full-fidelityrow-gapstorage requires a new bit slot incss_computed_style_i.bits[].- JPEG photo plot still slow when scrolling — pre-scale at decode time is partially shipped (fixes162 + fixes259), but real-content scroll jank persists. Per-tick re-decode vs cached display-size bitmap is the next look.
Build
MacSurf.mcp did not need to add any new .c files for v0.7 — every fix touched existing source files. Three header-level cleanups in fixes271b across box.h, layout_internal.h, layout.c. CW8 partition unchanged (16 MB preferred / 8 MB minimum).
SheepShaver smoke
OS 9.0.4 in SheepShaver still good for Carbon init / UI / rendering smoke. Networking remains the SheepShaver limitation; not a substitute for hardware fetcher testing.
Download
- MacSurf.sit — ready-to-run StuffIt archive. Expand on Mac OS 9.1+ with CarbonLib 1.5+ and launch.
- Source: this repository at tag
v0.7.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About MacSurf
All releases →Related context
Related tools
Beta — feedback welcome: [email protected]