Skip to content

feat: ctxClip takes the fill rule ctxFill takes, so a ring clipped evenodd cuts a ring where it cut the square around it - #12

Merged
sidorares merged 1 commit into
mainfrom
fix/clip-evenodd
Oct 3, 2026
Merged

sidorares merged 1 commit into
mainfrom
fix/clip-evenodd

Conversation

@sidorares

Copy link
Copy Markdown
Contributor

ctxClip now takes the boolean ctxFill takes, as ctxClip(surface, evenOdd): the clip geometry is built with D2D1_FILL_MODE_ALTERNATE when it is set and D2D1_FILL_MODE_WINDING when it is false or absent, so every existing caller clips as it did. The macOS half is windowkit/appkit#111.

Why now. ntk 8.22.0's SvgView cuts an element to its <clipPath> with canvas's ctx.clip(path, rule), the rule being the shape's clip-rule (sidorares/ntk#529). react-x11's Windows context dropped the rule and CtxClip always called BuildPath winding, so an SVG ring clipped evenodd came out a filled square where X11 draws a ring. The react-x11 half hands the flag on; it is a no-op until this lands and core's range moves to the release.

The rect fast path. One rect still takes PushAxisAlignedClip whatever the rule: one figure wound once is cut alike by both.

Test. test/clip-rule.js, in test:unit, the job that gates CI, fills a surface through a clip to a ring of two rects wound the same way:

  • evenodd leaves the hole empty;
  • no flag, or false, fills it, as before;
  • one rect, the PushAxisAlignedClip route, clips to the same pixels under both rules.

Not built locally. This was written on a Mac, so CI here is the first build and the first run of the test. The same test against the appkit build fails before its change and passes after.

…enodd cuts a ring where it cut the square around it

ctxClip(surface, evenOdd) builds its geometry with D2D1_FILL_MODE_ALTERNATE
when the flag is set and D2D1_FILL_MODE_WINDING otherwise, the same flag and
default as ctxFill. canvas's clip(path, 'evenodd') is how ntk's SvgView cuts
an element to a <clipPath> with clip-rule="evenodd" (sidorares/ntk#529),
and react-x11's context hands it on now; CtxClip ignored a second argument
and built every clip geometry winding.

One rect still takes PushAxisAlignedClip under either rule: one figure
wound once is cut alike by both.
@sidorares
sidorares merged commit 9380558 into main Oct 3, 2026
7 checks passed
@sidorares
sidorares deleted the fix/clip-evenodd branch October 3, 2026 23:10
sidorares added a commit to sidorares/react-x11 that referenced this pull request Oct 4, 2026
…a clip the context hands evenodd is cut evenodd on macOS and Windows, and the smoothing a perspective's tiles ask for reaches a Mac, where the ranges admitted neither bridge's verb

neither bridge read it: an SVG ring clipped evenodd by ntk 8.22.0's
SvgView, or an `<Html>` polygon cut evenodd, still came out the square
around it. appkit 0.24.0 clips with CGContextEOClip for the flag
(windowkit/appkit#111), win32 0.0.7 builds the clip geometry alternate
(windowkit/win32#12). Both ranges were exact on 0.x.

The appkit range also reaches 0.23.0's ctxSetImageSmoothing
(windowkit/appkit#109). #861 feature-detects it, so a context made over
an install that `^0.22.0` resolved kept every tile of a box in
perspective at medium quality, resampling the whole surface for each.

test/backend-context-clip-rule.test.js gains a layer over the real
bridge, where it loads: a ring clipped evenodd, by the current path and
by a path handed in, leaves its hole undrawn. It fails on 0.22.0 at the
hole and passes on 0.24.0. docs/macos.md says what the rule does and
where it came from, and the Windows verb table names the fill mode.
sidorares added a commit to sidorares/react-x11 that referenced this pull request Oct 4, 2026
…a clip the context hands evenodd is cut evenodd on macOS and Windows, and the smoothing a perspective's tiles ask for reaches a Mac, where the ranges admitted neither bridge's verb

#864 hands the fill rule to `ctxClip` as the flag `ctxFill` takes, and
neither bridge read it: an SVG ring clipped evenodd by ntk 8.22.0's
SvgView, or an `<Html>` polygon cut evenodd, still came out the square
around it. appkit 0.24.0 clips with CGContextEOClip for the flag
(windowkit/appkit#111), win32 0.0.7 builds the clip geometry alternate
(windowkit/win32#12). Both ranges were exact on 0.x.

The appkit range also reaches 0.23.0's ctxSetImageSmoothing
(windowkit/appkit#109). #861 feature-detects it, so a context made over
an install that `^0.22.0` resolved kept every tile of a box in
perspective at medium quality, resampling the whole surface for each.

test/backend-context-clip-rule.test.js gains a layer over the real
bridge, where it loads: a ring clipped evenodd, by the current path and
by a path handed in, leaves its hole undrawn. It fails on 0.22.0 at the
hole and passes on 0.24.0. docs/macos.md says what the rule does and
where it came from, and the Windows verb table names the fill mode.
sidorares added a commit to sidorares/react-x11 that referenced this pull request Oct 4, 2026
…a clip the context hands evenodd is cut evenodd on macOS and Windows, and the smoothing a perspective's tiles ask for reaches a Mac, where the ranges admitted neither bridge's verb (#865)

#864 hands the fill rule to `ctxClip` as the flag `ctxFill` takes, and
neither bridge read it: an SVG ring clipped evenodd by ntk 8.22.0's
SvgView, or an `<Html>` polygon cut evenodd, still came out the square
around it. appkit 0.24.0 clips with CGContextEOClip for the flag
(windowkit/appkit#111), win32 0.0.7 builds the clip geometry alternate
(windowkit/win32#12). Both ranges were exact on 0.x.

The appkit range also reaches 0.23.0's ctxSetImageSmoothing
(windowkit/appkit#109). #861 feature-detects it, so a context made over
an install that `^0.22.0` resolved kept every tile of a box in
perspective at medium quality, resampling the whole surface for each.

test/backend-context-clip-rule.test.js gains a layer over the real
bridge, where it loads: a ring clipped evenodd, by the current path and
by a path handed in, leaves its hole undrawn. It fails on 0.22.0 at the
hole and passes on 0.24.0. docs/macos.md says what the rule does and
where it came from, and the Windows verb table names the fill mode.
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