Skip to content

Snap solid filled rectangles to whole pixels in the web (Canvas 2D) backend #638

Open

Description

@Velli20

Follow-up to #637.

Problem

#637 makes the Skia backend fill a solid, axis-aligned rectangle snapped to the nearest pixel edges without anti-aliasing, so thin barcode bars (e.g. TCPDF's x y w h re f bars, ~1.13 pt wide with ~1.13 pt gaps) stay solid and separate.

The web backend (pdf-graphics-web) does not do this. WebCanvasBackend::fill_path (crates/pdf-graphics-web/src/web_canvas_backend.rs) sends every path to Canvas 2D at its exact fractional coordinates, and Canvas 2D always anti-aliases fills. Thin bars therefore render grey-edged and narrower than in Skia/PDFium — most visibly at 1x zoom on standard-density displays.

Proposed change

Reuse the backend-agnostic helpers added in #637:

  1. In fill_path, when there is no shader, compute the mapping from logical device space to backing pixels (it includes viewport.device_to_backing(), i.e. the devicePixelRatio scale).
  2. Call CanvasPath::axis_aligned_rect(&to_pixels); if it returns a rectangle, take Rect::snapped_to_pixels().
  3. Draw it with fillRect under an identity transform (restoring the transform afterwards). With integer edges, Canvas 2D's anti-aliasing produces no partial coverage.
  4. Otherwise fall through to the existing path fill.

Snapping must happen in backing pixels, not logical device units; snapping before the DPR scale would misplace edges on high-density displays and could merge bars again.

Verification

  • cargo xtask web-canvas --profile debug --serve --port 8080, open a barcode page (e.g. TCPDF example 027) at DPR 1 and 2: bars solid black and separated.
  • Clip, blend mode, constant alpha, and soft masks still apply to snapped fills.

FemtoVG could get the same treatment separately.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions