Skip to content

Support lossless zero-blur box shadows - #2849

Closed
claell wants to merge 2 commits into
Kozea:mainfrom
claell:codex/vector-zero-blur-shadows
Closed

Support lossless zero-blur box shadows#2849
claell wants to merge 2 commits into
Kozea:mainfrom
claell:codex/vector-zero-blur-shadows

Conversation

@claell

@claell claell commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Partially addresses #13.

Summary

  • Parse and compute the CSS box-shadow grammar when every blur radius is zero.
  • Paint multiple outer and inset shadows in the specified front-to-back order.
  • Support offsets, positive and negative spread, explicit colors, currentColor, rounded corners, transparent-box knockout, and collapsed-border table rules.
  • Keep PDF output lossless and scalable by representing shadows entirely as vector paths.
  • Reject nonzero blur radii with an actionable warning instead of silently accepting an effect that cannot be painted faithfully by this implementation.

Rationale

The previous implementations in #149 and #859 rasterized shadows. That adds image data to PDF output, scales poorly, and was the central reason those approaches were not merged.

Zero-blur shadows do not have that constraint: their sharp perimeters can be represented directly with PDF paths. A maintainer explicitly noted that this subset would be useful and invited further work in the #13 discussion: #149 (comment).

This pull request deliberately implements only that lossless subset. It does not introduce Pillow, a blur library, image surfaces, or any new dependency. Blurred shadows, text-shadow, and filter: drop-shadow() remain separate concerns with different painting and output-policy tradeoffs.

Implementation notes

  • Outer shadows use the border box and are knocked out inside that box even when its background is transparent.
  • Inset shadows use the inverse of the shifted padding-box perimeter and are clipped to the rounded padding edge.
  • Spread-adjusted radii follow the current CSS Backgrounds radius-expansion algorithm, including its coverage correction for rounded shapes.
  • Outer shadows are skipped on internal table boxes in the collapsing-border model; inset shadows remain paintable.
  • Shadows are marked as PDF artifacts and participate in the existing transform, opacity, clipping, and stacking machinery.

Verification

  • 913 CSS validation tests pass.
  • 9 generic shadow drawing tests pass, covering outer and inset painting, transparent knockout, layer order, spread and currentColor, rounded geometry, negative inset spread, collapsed tables, and vector-only PDF output.
  • The complete suite reports 4,282 passed and 41 expected failures. The sole failure is the pre-existing Windows path-with-spaces behavior in test_command_line_render, where the test helper applies args.split() to this checkout's absolute path.
  • Ruff reports no issues in the changed Python and test files.
  • A generic six-case HTML specimen was rendered to PDF with Ghostscript 10.07.1 and visually inspected. No project-specific data or fixtures are included.

The full suite used the Windows Ghostscript discovery from #2847 as a temporary local test-harness change; that unrelated change is not included in this branch.

AI assistance disclosure

This change was authored with ChatGPT Codex under human direction and review. Maintainer review remains necessary, particularly for CSS conformance, painting integration, and long-term architecture.

claell added 2 commits July 18, 2026 14:10
* Validate the complete shadow grammar while rejecting nonzero blur radii with actionable diagnostics.
* Compute absolute lengths and currentColor for painting.
* Cover valid and invalid syntax, colors, inset, spread, and multiple shadows.
* Paint outer and inset shadows in CSS order with knockout, spread, and current rounded-corner rules.
* Respect collapsed-border table behavior and preserve vector-only PDF output.
* Document the supported subset and cover generic rendering behavior.
@liZe

liZe commented Jul 28, 2026

Copy link
Copy Markdown
Member

Thanks for this pull request.

We opened a shorter and more simple pull request, that also handles blur: #2863.

@liZe liZe closed this Jul 28, 2026
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.

2 participants