docs(2d): how strong a blurred shadow gets, and how to test one - #288
Merged
Conversation
Issue #287 reported that shadows paint nothing on node-x11's in-process JS X server. They paint exactly what Xorg paints. Rendering the issue's own snippet on both servers with the same pinned font gives byte-identical pixels, for `fillText` and for `TextLayout.draw` alike, and the same holds for rects, paths, strokes and images across blur sizes. What the report actually found is how strong a blurred shadow gets. A blur is coverage convolved with a gaussian, so a shadow only reaches `shadowColor` where the shape casting it is wide compared with the blur. A 60x40 rect at `shadowBlur: 30` peaks at 0.78 alpha; 48px glyph stems at `shadowBlur: 14` peak at 0.37, because a five-pixel stem against sigma 7 keeps under a third of its coverage. So a "count pixels within 90 of #ff0000" assertion finds nothing on a canvas whose red glyph shadow is plainly visible - on any server, including Xorg. Nothing to fix in `lib/`; what was missing was the number and a test that holds both servers to it. - docs/context-2d.md: a section on the peak alpha a shadow reaches, with the three measured numbers, and what to assert instead of a colour - docs/xserver.md: filtering is exact on the JS server even though rasterization is not, so a vanishing shadow there is an assertion problem, not a missing request - test/shadow.test.js: the wide-shape case pinned at 200/255 and the 48px glyph case at ~94/255, hermetically - test/smoke-canvas.test.js: the same 0.784 asserted against Xorg, which is the cross-server claim nothing was checking
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #287.
What I found
Shadows are not missing on the in-process JS X server. They paint exactly
what Xorg paints.
Drawing the issue's own snippet on both servers, with the same pinned font
so the glyphs are identical, gives byte-identical pixels —
fillTextandTextLayout.drawalike, and the same for rects, paths, strokes and imagesacross blur sizes. Nothing in
lib/needed changing, so nothing inlib/changed.
What the report actually found is how strong a blurred shadow gets. A
blur is coverage convolved with a gaussian, so a shadow reaches
shadowColoronly where the shape casting it is wide compared with theblur:
shadowBlurA five-pixel stem against sigma 7 keeps about 0.28 of its coverage,
which is the gaussian's own answer, and it is what a browser draws too. So
countPixels(ctx, band, '#ff0000', 90)returns 0 on a canvas whose redglyph shadow is plainly visible — on any server, XQuartz included. The
comparison in the issue was a visual check on one server against an
exact-colour count on the other.
The picture
Same code, same font, two servers. Left is the in-process JS server with no
$DISPLAY; right is XQuartz. Differences outside the small captions: 21bytes in the glyph-shadow band and 174 in the rect band, none larger than 1.
The captions differ because small-glyph rasterization is deliberately not
pixel-exact, which
docs/xserver.mdalready said.What changed
the three measured numbers, and what to assert instead of a colour: the
shadow's own alpha on a transparent target, a difference between two
places, or the gaussian's CDF profile.
even though rasterization is not, so a shadow that seems to vanish under
a headless harness is an assertion problem rather than a missing request.
and the 48px glyph case at about 94/255, with the reason in the comment.
That cross-server equality is the claim the issue needed and nothing was
checking.
For the react-x11 side
The font explorer's shadow is testable as it stands. Assert the shadow's
alpha rather than its colour: draw with
fillStyletransparent so only theshadow paints and read the alpha channel, or compare a pixel in the shadow
against one outside it. An exact
#ff0000count will keep returning 0 onXQuartz too.