Changelog --------- Development =========== - ABI: LWS_PRE, the headroom that has to be valid before any buffer passed to lws_write(), grew from 16 to 32 bytes on 64-bit builds (28 with 4-byte pointers): the largest ws frame header (10) plus the client-side mask (4) plus the 9-byte h2 DATA frame header that is prepended in place when ws is carried over h2 (RFC 8441) did not fit in 16, so a ws-over-h2 frame of 126+ bytes (client) or 64KB+ (server) wrote up to 7 bytes before the caller's buffer. Code compiled against an older libwebsockets.h leaves too little headroom for this library: rebuild everything that uses LWS_PRE (or the legacy LWS_SEND_BUFFER_PRE_PADDING) against the new headers, and always spell the headroom LWS_PRE rather than a literal. The library now fails to build if LWS_PRE is ever made smaller than the in-place prepends it performs (ws + h2, h3 + webtransport). - lhp: css background-size and background-position are applied to css background images, with lengths in any unit, percentages (of the element box for size, of the element-less-image for position) and the left/center/right/top/bottom keywords; an auto side follows the intrinsic aspect ratio when the image dimensions arrive. The slashdot capture's logo now draws like the real thing: 146px wide (22px tall) 20px in from the left of its 167x35 element, instead of stretched to the element. text-indent is supported (inherited, first line of the block), which also implements the classic "text-indent: -9999px" idiom for hiding the text of an element that shows an image instead: the "Slashdot" anchor text no longer renders over the logo, and the element keeps its box so following content flows around the graphic rather than over it. An older heuristic that marked text-indent <= -999px elements wholly hidden (it had never fired, because negative values did not parse) is removed: it hid the element box while the background image still drew, leaving the graphic colliding with the following menu. Case 12-bg-position covers the sizing, positioning and indent hide. - lhp: negative css values never parsed: a leading '-' did not start a number, so lengths like "margin-left: -32px" were silently kept as strings and ignored. The value lexer now accepts a leading minus, so negative lengths and percentages work everywhere; the lobsters capture's negative margins now apply and its golden was regenerated for that. - lhp: document asset fetches are now queued behind an fd-budgeted number of in-flight slots instead of all connecting at once. The ceiling adapts to the context's fd limit (tiny fd tables end up serializing their fetches instead of failing them, and fat boxes are still capped at 16), and at most 4 assets may be in flight to the same scheme://host[:port] at once: servers rate-limit parallel connections from one client, and blasting a dozen TLS connections at one CDN gets the extra ones silently hung until they time out. Queued assets whose server is at its per-host ceiling are passed over for later ones on other servers. Completed image assets release their slot at end of message rather than squatting on it until teardown, an asset already fetching or queued is reused when the document repeats its url instead of fetching it again, and a document whose own stream has ended defers deciding it is complete until its outstanding assets have arrived or failed. Image dimension callbacks only fill in missing dlo box sizes, so css- or attribute-sized images keep their size. The lhp-dlo test tool gained --fd-limit to try layouts against small targets, and case 11-asset-queue covers six images arriving through a serialized queue on a 6-fd context. - svg: the rasterization scratch (crossings and the aa per-column terms) is now a single refcounted pool shared by every live svg object — it carries no state between lines, so a page of n simultaneously-visible svgs costs one 4KB scratch rather than n. It grows to the largest demand seen, shrinks by doubling steps when the largest-demand object is destroyed, and frees with the last object. Interleaved rendering of two live objects on the shared pool is regression-tested - svg: the whole svg object (context, working buffers, stylesheets and scene) now lives in a single lwsac freed with one call — the working buffers grow by chained doubling generations inside it, bounded by the existing caps. The peak simultaneous heap footprint is tracked (as the lwsac total) and logged at destroy time. svg.c is also split into the parse side (svg.c) and the rasterization side (svg-raster.c), sharing a private header - svg: exact-area antialiasing. With lws_svg_render_t.aa set, coverage is the exact covered fraction of each pixel, computed as the winding integral over the pixel from band-clipped boundary edges contributing clipped-linear ramp areas (the FreeType-class cell/area approach, in pure integer arithmetic — no supersampling): corners inside a pixel, thin features and slivers between scanlines are exact, spans split where the fraction changes, and alpha carries fill alpha x coverage through the existing compositing. Binary centre-sampled coverage remains the default; the dlo integration and the eyeball tool render antialiased. Includes exact half/quarter-pixel and 45-degree boundary checks in lws-api-test-svg - svg: the renderer is now pure integer arithmetic end-to-end, on the lws_fx fixed-point basis: Q16.16 saturating coordinates, transforms and raster math, and e8 (1e-8) parse values, angles and opacity via the lws_fx operators. No floating point, FPU or libm dependency remains; output is bit-identical across platforms, and saturating products replace the overflow-to-inf class of bugs (closes audit finding F-064, where hostile nested scale() transforms could produce inf/NaN scene points reaching qsort with an inconsistent comparator and (int) casts of non-finite doubles). The corpus triangle oracle is now exact integer arithmetic (the previous double oracle landed on the wrong side of exact half-pixel boundaries by fp luck) - svg: minimal CSS support from