Skip to content

feat: ctxRoundRectXY and op 9, a rounded rect whose corners are elliptical - #10

Merged
sidorares merged 1 commit into
mainfrom
feat/round-rect-xy
Sep 29, 2026
Merged

sidorares merged 1 commit into
mainfrom
feat/round-rect-xy

Conversation

@sidorares

Copy link
Copy Markdown
Contributor

appkit's new verb, for the Windows bridge: ctxRoundRectXY(surface, x, y, w, h, tlx, tly, trx, try, brx, bry, blx, bly), a rounded rect whose corners are elliptical, each its own pair of radii. Canvas's roundRect takes an { x, y } point for a corner and CSS a border-radius: 40px / 20px, and react-x11 had been drawing those square. Each corner is one of Direct2D's own elliptical arc segments, and a corner with no extent on one axis is square rather than cut off diagonally.

ctxPath reads it as op 9, twelve numbers after the op. A bridge that answers ctxRoundRectXY reads op 9 too, which is how react-x11 knows it may send one; an older bridge, which stops reading at an op it does not know, is sent the corners as curves. Four corners alike are one Direct2D rounded rect, which has an x and a y radius of its own, so they take the primitive route as circular ones do.

test/path-stream.js draws op 9 in the stream the same as the verb, and test/primitives.js holds a uniform elliptical rounded rect's primitive to its path and checks elliptical and square corners of their own. Written on a Mac, so CI here is its first build.

…tical

appkit's verb: each corner its own pair of radii, drawn with Direct2D's own
elliptical arc segments, square where a corner has no extent on one axis.
ctxPath reads it as op 9, which is how react-x11 knows it may send one; an
older bridge is sent the corners as curves. Four corners alike are one
Direct2D rounded rect, which has an x and a y radius of its own.
@sidorares
sidorares merged commit bb4cb30 into main Sep 29, 2026
7 checks passed
sidorares added a commit to sidorares/react-x11 that referenced this pull request Sep 29, 2026
…aw an elliptical corner whole

ntk 8.16.1 is sidorares/ntk#471: the tile plan and pixels this context draws
shadows from. @windowkit/appkit 0.17.0 and @windowkit/win32 0.0.6 answer
ctxRoundRectXY, windowkit/appkit#90 and windowkit/win32#10; the context
feature-detects it, so an older bridge still draws the corners as curves.
sidorares added a commit to sidorares/react-x11 that referenced this pull request Sep 30, 2026
…le made once (#794)

* perf(backend): a rect's or a rounded rect's shadow is drawn from a tile made once

CoreGraphics blurs a shadow on every fill that has one set, at the cost of
the shape's area times the blur's width. On a 2x display a page header's
box-shadow: inset 0 0 100px, repainted by every strip a scroll exposed, was
130 to 380 ms, and a card's 200px hover shadow 110 ms: Zen Garden's home page
scrolled at 11 to 14 frames a second wherever the header or the footer was
in view, and its all-designs page at 18 with the pointer over a card.
Direct2D draws no live shadow at all.

The context Cocoa and Windows share now recognises the shapes a box shadow
is made of: a fill of a path that is one rect or one roundRect, or two of
them one inside the other filled evenodd, the frame an inset shadow is cast
around, and a fillRect. Their shadow comes from a tile. A rounded rect's
shadow is the same all along its straight edges, so it is made once for a
copy of the shape shortened to three pixels of straight edge and drawn in
up to nine pieces, the straight pixel stretched between the corners. The
tile is named by the corners, the blur, the hole and the colour, not by
where the shape is or what part a paint reaches: every card with one shadow
shares it, and a scroll strip draws a strip of it. ntk plans it and makes
its pixels, ntk/shadow-tiles, the code X11's shadows come from too. The
header's inset shadow is 4 ms, and with the document drawing through it the
same pages scroll at 50 to 60. A tiled shadow is the canvas spec's
gaussian, sigma half the blur, within six levels of the exact one.
REACT_X11_NO_SHADOW_TILES=1 puts every shadow back on the bridge.

A blurred box shadow draws on macOS and Windows. It was baked on an X
server, and without one it drew nothing; now it is the context's own
shadow, which is a tile.

roundRect takes its radii as canvas has them: a number, an { x, y } point
for an elliptical corner, or a list of one to four of either, scaled down
together where two corners on a side would meet. It took numbers alone and
drew an { x, y } corner square. Elliptical corners go to the bridge as
ctxRoundRectXY where it has one, and as op 9 in the ctxPath stream, and as
curves where it does not.

Needs ntk with ntk/shadow-tiles.

* chore(deps): ntk 8.16.1 for ntk/shadow-tiles, and the bridges that draw an elliptical corner whole

ntk 8.16.1 is sidorares/ntk#471: the tile plan and pixels this context draws
shadows from. @windowkit/appkit 0.17.0 and @windowkit/win32 0.0.6 answer
ctxRoundRectXY, windowkit/appkit#90 and windowkit/win32#10; the context
feature-detects it, so an older bridge still draws the corners as curves.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant