Skip to content

Paint button widget appearances in the web annotation layer - #672

Merged
Velli20 merged 1 commit into
mainfrom
web-paint-widget-appearances
Oct 31, 2026
Merged

Velli20 merged 1 commit into
mainfrom
web-paint-widget-appearances

Conversation

@Velli20

@Velli20 Velli20 commented Oct 31, 2026

Copy link
Copy Markdown
Owner

Summary

In the web stack (pdfium-web), checkbox, radio and push-button widgets used to show as native browser controls (blue checkboxes, push buttons showing only their field label). PDFium draws each widget's /AP appearance stream instead. This PR paints those appearances on the page canvas, matching PDFium.

  • Core (pdf-annotation-core):
    • AppearanceDictionary keeps the resolved /AP /N and /D entries. They are unparsed and not serialized.
    • WidgetControl.painted marks button widgets that have an appearance.
    • AnnotationOverlay::painted_appearances(page, pressed) returns each displayed widget's appearance under its live state: the on-state or Off, /AS for push buttons, and /D while pressed.
  • Renderer: PdfRenderer::render_annotation_appearances maps each form's transformed /BBox onto /Rect (ISO 32000 §12.5.5). It draws through the existing content-stream path after the page content, without recording selectable text. An appearance stream that can't be read is skipped.
  • pdf-web:
    • WebPageRenderer::render paints the appearances. The conformance --renderer web harness goes through this path too.
    • Painted controls are transparent (native-painted), so they still take clicks and keyboard focus.
    • Non-button fields get PDFium's form highlight, rgb(221 228 255) at alpha 100/255, through --native-form-highlight.
    • A new optional onPress callback reports a painted widget being held down, so the host can draw its down appearance.
  • Example host: WebDocument::repaint and WebDocument::press re-render a page with its stored viewport, after edits and while a widget is held down.

Testing

  • cargo clippy with -D warnings on the changed crates, natively and for wasm32-unknown-unknown.
  • cargo fmt --check, cargo test on the changed crates, and cargo xtask annotation-types --check.
  • Rendered action_hide_show_form.pdf (from the PDFium corpus) through the new appearance pass on Skia. The checkbox and radio glyphs, the button logos and the captions match PDFium.
  • Viewed in the browser (cargo xtask web-canvas). The glyph and highlight colours match PDFium's render: glyphs (87,89,99), field background (242,244,254).
  • Not checked: the pressed (/D) appearance has only been built, not seen in a browser or rendered through Skia.

Not run locally: clippy with --all-features, which needs a Skia build with GL/PDF features that isn't cached here, and the tsc type check, which isn't installed. CI runs both.

🤖 Generated with Claude Code

Checkbox, radio and push-button widgets now draw their /AP appearance
streams on the page canvas instead of showing native browser controls.
The HTML controls stay on top as transparent hit and input targets.

- Core keeps the resolved /AP /N and /D entries and reports, per page,
  the appearance each displayed button widget paints under live field
  state (on-state or Off, /AS for push buttons, /D while pressed).
- PdfRenderer::render_annotation_appearances maps each form's transformed
  /BBox onto /Rect and draws it after the page content, without
  recording selectable text.
- The web layer marks painted controls, hides their native look, lays
  PDFium's light-blue form highlight over non-button fields, and
  repaints the page after edits and while a widget is held down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Velli20
Velli20 merged commit ab653fa into main Oct 31, 2026
10 checks passed
@Velli20
Velli20 deleted the web-paint-widget-appearances branch October 31, 2026 18:19
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