Skip to content

Use stroked dashes for uniform dotted and dashed borders#2776

Open
Dino0204 wants to merge 3 commits into
Kozea:mainfrom
Dino0204:fix/2526-dotted-border-size
Open

Use stroked dashes for uniform dotted and dashed borders#2776
Dino0204 wants to merge 3 commits into
Kozea:mainfrom
Dino0204:fix/2526-dotted-border-size

Conversation

@Dino0204
Copy link
Copy Markdown

@Dino0204 Dino0204 commented May 24, 2026

Fix #2526.

For uniform dotted borders with no rounded corners, stroke one line per
side with a round line cap and a zero-length dash pattern instead of
emitting a filled Bézier circle per dot. Each dot becomes a round-cap of
the stroke, so we replace ~24 numbers per dot with one moveto +
lineto + dash setup per side.

Any other dotted case (mixed colors, different widths, rounded corners)
falls through to the existing slow path.

Results

Repro case from the issue (<body style="border: 1px dotted black">):

Metric Before After
PDF size 34,445 B 836 B
curve_to operators in content stream 2,544 0

Equivalent dashed repro (<body style="border: 1px dashed black">):

Metric Before After
PDF size 1,185 B 829 B

5-case visual sample (1px / 3px / 5px uniform dotted, border-radius, 4
different colors). BEFORE on the left, AFTER on the right. Cases 4 and
5 take the slow path unchanged.

Metric Before After
PDF size 102 K 53 K
Pixel diff vs before (150 DPI) 0.02% (anti-alias noise only)

Same layout for dashed:

Metric Before After
PDF size 6,313 B 5,590 B
Pixel diff vs before (150 DPI) 0.14% (anti-alias noise only)

Iteration

The first attempt (27896e4) stroked a single closed rectangle with one
dash period applied across the entire perimeter. That collapsed the
whole border into one re + dash, but because the perimeter is rarely
an integer multiple of 2 × width, dots near the corners landed
slightly off — visible especially in the 5px case below:

visual-compare-v1

The second commit (2e3ef79) strokes each side individually and picks
the dash period per side so dots land exactly on both corners, matching
the per-side spacing of the generic path. Corners snap to dots, and the
pixel diff against the generic path drops from 0.6% to 0.02%:

visual-compare

The third commit (7544edfc) extends the same function to handle
dashed borders, per @liZe's suggestion. The dotted/dashed split is
contained to three small knobs (cap, inset, dash array); net delta vs
the dotted-only version is +12 effective lines.

dashed-visual-compare

Tests

  • pytest -k 'dotted or border': 404 passed, 2 xfailed (same as main)
  • pytest -k 'dashed': passes, no new failures
  • pytest: no new failures
  • ruff check: clean

@liZe
Copy link
Copy Markdown
Member

liZe commented May 25, 2026

Thanks a lot!

@liZe
Copy link
Copy Markdown
Member

liZe commented May 25, 2026

@Dino0204 The idea is cool, the pull request is OK, but we’ll wait after 69.0 to merge because the release is already huge and late.

Do you think there’s a way to adapt the function for dashes? If the result is short and readable, it may be interesting to handle them both.

@liZe liZe added the feature New feature that should be supported label May 25, 2026
@Dino0204
Copy link
Copy Markdown
Author

@Dino0204 The idea is cool, the pull request is OK, but we’ll wait after 69.0 to merge because the release is already huge and late.

Do you think there’s a way to adapt the function for dashes? If the result is short and readable, it may be interesting to handle them both.

Thank you for the suggestion. I will look into extending the function to cover dashes as well!

@Dino0204 Dino0204 changed the title Use stroked dashes for uniform dotted borders Use stroked dashes for uniform dotted and dashed borders May 26, 2026
@Dino0204
Copy link
Copy Markdown
Author

@liZe Took a shot at this in e626fe9 would appreciate your review on the approach. The PR description has been updated accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature that should be supported

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants