# Changelog

## 0.9.0 - 2026-08-07

### Added

- Added generated CSS content for `::before` and `::after`, including quoted
  `content` fragments and `attr(...)` values.
- Added attribute-presence and attribute-equality selectors, `:not(...)`,
  odd/even `:nth-child(...)`, and `:first-of-type` and `:last-of-type`
  selectors for document templates.
- Added named CSS counters through `counter-reset`, `counter-increment`, and
  `counter(name)`, including multiple counters and explicit integer values.
- Added browser-parity fixtures for generated content, counters, the expanded
  selector set, and `white-space: pre-line` rendering.
- Added a local quality matrix and matching GitHub Actions coverage for the
  supported Elixir 1.19 and 1.20 runtimes. The matrix checks compilation,
  formatting, unused dependencies, 100% test coverage, Dialyzer, and Chromium
  browser parity.
- Added code-style regression checks for the library's documented public API
  and function-head conventions.

### Changed

- Changed the minimum supported Elixir version from 1.18 to 1.19.
- Changed inline whitespace layout to collapse ordinary HTML whitespace across
  element boundaries, preserve normalized CRLF, CR, and LF line breaks with
  `white-space: pre-line`, retain explicit `<br>` breaks, and treat literal
  escaped newline sequences as text.
- Updated GitHub Actions dependencies to Node 24-compatible releases.
- Refactored HTML-to-PDF parser, style, layout, pagination, page-geometry, page
  furniture, and PDF visual-comparison internals without changing their public
  APIs.

### Fixed

- Fixed `rgba()`, eight-digit hexadecimal, and `transparent` CSS colors losing
  their alpha values. Text, backgrounds, and borders now write the required PDF
  transparency graphics states, including shaded border variants.
- Fixed PDF merging misclassifying an object as a page when `/Type /Page`
  appeared only in a nested dictionary. Page-tree traversal now uses the shared
  reader's semantic dictionaries and resolves indirect `/Kids` and `/Count`
  values.
- Fixed stream tokenization allowing a nested dictionary's `/Length` to replace
  or leak into the enclosing stream dictionary's length.
- Fixed source-order text extraction inserting spaces between consecutive PDF
  text-showing operations. Operator-defined continuity is now preserved across
  `Tj` and `TJ` operands and exposed through each span's `joins_previous?`
  field, while positioning, text-object, Form XObject, and graphics-matrix
  boundaries still begin separate segments.

## 0.8.0 - 2026-07-30

### Added

- Added opt-in running page furniture through `:page_furniture`, with
  independently configured headers and footers, `:default`, `:first`, `:odd`,
  and `:even` variants, first-page-only and except-first-page behavior, and
  `{{page}}` and `{{pages}}` tokens.
- Added complete supported page geometry shared by renderer options and bare
  `@page` rules: named and explicit page sizes, portrait and landscape forms,
  one-to-four-value margins, margin longhands, asymmetric layout, and explicit
  renderer-option precedence.
- Added bundled DejaVu Sans regular, bold, oblique, and bold-oblique fonts for
  deterministic Unicode glyph fallback after requested and configured font
  families.
- Added browser-parity coverage for page furniture, page-number tokens,
  asymmetric page geometry, paragraph fragmentation, border variants, flex and
  grid constraints, HTML character references, and multi-row table headers.

### Changed

- Changed `:stylesheets` entries to require explicit `{:css, css}` or
  `{:file, path}` tags. Bare strings are rejected so empty or comment-only CSS
  cannot be mistaken for a path and file access is always explicit.
- Changed font loading to reuse successful parsed font files through a
  supervised, bounded, process-wide cache. Cache entries invalidate when file
  metadata changes, concurrent cold loads are deduplicated, failed parses are
  not retained, and no host-application configuration is required.
- Changed the package metadata and documentation to identify the MIT,
  Bitstream Vera, and BSD 3-Clause licenses used by the source, bundled DejaVu
  fonts, and generated WHATWG character-reference data.
- Documented that repeated page furniture uses the explicit renderer option;
  CSS `position: fixed` remains deferred until positioned layout can remove
  elements from normal flow and apply offsets correctly.

### Fixed

- Fixed CSS cascade precedence so stylesheet `!important` declarations beat
  normal inline declarations, while inline `!important` declarations retain
  priority over important stylesheet declarations.
- Fixed table `rowspan` layout to reserve occupied columns and span the combined
  height of all covered rows.
- Fixed paragraphs taller than the remaining or complete printable page being
  clipped or kept together indefinitely; pagination now fragments them at
  complete visual lines, including oversized `break-inside: avoid` paragraphs.
- Fixed paginated tables repeating only one header row; all `<thead>` rows now
  repeat together when the table body continues.
- Fixed Unicode text being rejected or encoded with the wrong face by resolving
  each grapheme through the selected, requested, configured, and bundled
  fallback fonts before layout.
- Fixed text extraction across nested `q` and `Q` operators so saved graphics
  and text state is restored in LIFO order.
- Fixed Type 0 text width calculation by mapping source codes through the
  Encoding CMap before applying descendant CID widths, with strict diagnostics
  and resource limits for unsupported or malformed CMaps.
- Fixed merging pages with inherited or indirect `MediaBox`, `CropBox`,
  `Resources`, `Rotate`, `BleedBox`, `TrimBox`, `ArtBox`, and `UserUnit` values
  by materializing the nearest effective page-tree values.
- Fixed the shared reader accepting duplicate page-tree references or
  inconsistent descendant `/Count` values.
- Fixed ASCII85 decoding of delimiters, whitespace, `z` groups, partial final
  groups, and values that overflow the 32-bit group range.
- Fixed HTML named and numeric character references using the complete WHATWG
  table, including legacy semicolon rules, invalid numeric normalization,
  multi-code-point references, non-breaking spaces, and decode-once behavior.
- Fixed CSS custom properties being resolved before their cascade completed;
  ordinary declarations now use the final winning custom-property values.
- Fixed `none`, `hidden`, `dotted`, `dashed`, `solid`, `double`, `groove`,
  `ridge`, `inset`, and `outset` borders, including independent side styles and
  transparent border spacing.
- Fixed valid page-context declarations being rejected and malformed `size`,
  margin, orientation, marks, bleed, unknown, and incomplete declarations
  lacking actionable CSS diagnostics.
- Fixed zero, negative, or excessive margins being accepted when they leave no
  positive printable page area.
- Fixed merged output corrupting PDF names that require `#xx` escaping,
  including whitespace, delimiters, literal `#`, control bytes, and
  non-printable bytes.
- Fixed unsupported named or pseudo-page selectors and misspelled `@page`
  at-rules being silently applied to every page; they now return strict
  diagnostics.
- Fixed declaration-order-dependent computed CSS values by resolving `em`,
  `rem`, `currentColor`, relative semantic margins, custom properties, and
  inherited line heights against the element's final computed style.
- Fixed grid `minmax()` tracks discarding their minimum and added redistribution
  when fractional tracks reach a minimum bound.
- Fixed flex grow and shrink distribution overwriting item `min-width`,
  `max-width`, `min-height`, and `max-height` constraints.
- Fixed text extraction rejecting valid inherited indirect page `/Rotate`
  values.
- Fixed merge failures replacing the reader's machine-readable reason and
  diagnostic stage; callers can again distinguish encryption, page-tree,
  resource-limit, malformed-input, and unsupported-feature failures.
- Fixed valid empty or comment-only inline stylesheets and paths containing
  braces being misclassified by replacing content-based guessing with explicit
  stylesheet source tags.
- Fixed the public `:default_font` typespec so its documented fallback-list form
  accepts `[String.t()]`.
- Fixed a severe CSS `rem` performance regression that recursively traversed
  complete font registries and decoded runtime payloads for every element.
  Runtime font and image data is now opaque to CSS length resolution, with a
  deterministic reductions-based regression test.

## 0.7.0 - 2026-07-23

### Added

- Added local CSS `@font-face` support for embedded and configured
  stylesheets, including `font-family`, ordered `src: url(...)` fallbacks,
  `font-weight`, `font-style`, and supported `font-display` values.
- Added TrueType font loading from `.ttf` files and `.otf` files that use
  TrueType outlines. Relative font URLs resolve against the configured
  stylesheet directory or renderer `:base_url`.
- Added print media handling for `@media print`, `@media only print`,
  `@media all`, and `@media only all`, while non-print media rules are omitted
  from the active print cascade.
- Added PDF document metadata through the HTML renderer's `:metadata` option
  for title, author, subject, keywords, creation date, and modification date.
  Metadata dates accept `Date`, `NaiveDateTime`, `DateTime`, and ISO 8601
  strings, and non-ASCII values are written as Unicode PDF strings.
- Added automatic PDF title metadata from the first non-empty HTML `<title>`
  when no explicit metadata title is provided.
- Added Chromium parity coverage for CSS-declared fonts and print media, plus
  examples and compatibility documentation for fonts, print CSS, metadata,
  supported formats, URL resolution, and conversion boundaries.

### Changed

- Changed configured stylesheet handling to preserve each file's directory for
  relative assets and to apply configured `@page` rules when deriving default
  page options.
- Changed explicit and CSS-declared font registration to try ordered local
  source candidates until a supported font loads.
- Changed PNG decoding to stream decompression, require the exact expected
  decoded size, and reject images whose decoded scanlines exceed 100 MB.
- Changed RunLengthDecode to operate on binaries and enforce the PDF reader's
  decoded-stream and decompression-ratio limits.
- Changed text extraction to accumulate spans and output text without repeated
  list or binary copying, and capped extraction at 25,000 text spans per page
  with a `:resource_limit_exceeded` diagnostic.
- Changed merge failures to retain the PDF reader's reason and stage in the
  actionable merge diagnostic.

### Fixed

- Fixed merging PDFs that contain unrelated or stale catalog objects by
  resolving the active catalog from the trailer's `/Root` reference.
- Fixed hexadecimal strings with non-hexadecimal bytes being silently
  sanitized; the tokenizer now emits `:invalid_hex_string` with the offending
  byte position.
- Fixed PDF `DateTime` metadata formatting so UTC and non-UTC offsets are
  encoded correctly.
- Fixed CSS `@font-face` parsing for quoted URLs containing commas, ordered
  fallback sources, invalid or missing descriptors, unsupported formats, and
  malformed declarations.
- Fixed CSS diagnostics for malformed font and media rules so rendering returns
  actionable `:invalid_css` details with source, line, and column context.

## 0.6.0 - 2026-07-20

### Added

- Added `NativeElixirPdfUtilities.Pdf.Reader`, a shared PDF document layer with
  classic cross-reference tables, cross-reference streams, object streams,
  incremental and hybrid revision chains, recursive indirect resolution,
  supported stream filters, page-tree validation, and resource limits.
- Added committed reader fixtures for classic, xref-stream, object-stream,
  hybrid, incremental, encrypted, and malformed PDFs.
- Added `Text.extract_spans/2` and `Text.extract_file_spans/2` for
  page-preserving decoded text operations with source indexes, baseline
  coordinates, font and matrix context, and text rendering-mode metadata.
- Added strict Unicode decoding for standard simple-font encodings,
  font-specific `Differences`, Adobe glyph names, Type 0 fonts, and ToUnicode
  CMaps.
- Added PDF reader, text extraction, and merging guides covering supported
  structures, public behavior, diagnostics, limits, and known boundaries.
- Added GitHub Actions checks for compilation warnings, formatting, unused
  dependencies, tests, 100% coverage, Dialyzer, and Chromium browser parity.

### Changed

- Changed text extraction and PDF merging to consume the shared reader model so
  both utilities honor active revisions, generations, free entries, compressed
  objects, and the validated page tree.
- Changed text extraction to reject malformed content and unreliable font
  encodings with actionable diagnostics instead of guessing or returning
  partial text.
- Changed string extraction to project from the same positioned page spans
  while preserving the existing `layout: true` and `layout: false` output.

### Fixed

- Fixed merging pages with malformed inherited `/MediaBox` values by applying
  the default page box.
- Fixed valid cross-reference offsets that point to PDF whitespace immediately
  before an indirect object header being rejected.
- Fixed tokenizer comments ending at end-of-input being emitted as tokens.

## 0.5.1 - 2026-07-10

### Changed

- `Merge.merge/1` now rejects malformed classic PDF input with an
  `:invalid_pdf_input` diagnostic rather than producing an empty PDF or raising.
- `NativeElixirPdfUtilities.Tokenizer` now emits explicit error tokens for
  unterminated literal and hexadecimal strings.
- `Text.extract/2` rejects malformed token streams with an `:invalid_pdf_input`
  diagnostic. It also ignores unusually large ToUnicode CMaps to bound memory
  and CPU use during extraction.

### Fixed

- Fixed merge crashes caused by malformed tokens, incomplete streams, duplicate
  object identifiers, and invalid object identifiers.
- Fixed merged PDFs losing inherited `/MediaBox` and `/Resources` values from
  intermediate `/Pages` tree nodes.
- Fixed remapping of non-page `/Parent` references during a merge.
- Fixed malformed TTF font input causing HTML-to-PDF rendering to crash.
- Reduced avoidable repeated binary and list copying while writing larger PDFs.

## 0.5.0 - 2026-07-10

### Added

- Added `NativeElixirPdfUtilities.Diagnostics` as the shared public diagnostic contract.
- Added standardized diagnostic details for merge, text extraction, HTML rendering,
  pagination, PDF writing, and file failures.
- Added developer guidance for using the shared diagnostics contract in future public APIs.
- Added a diagnostics guide under `docs/`.

### Changed

- Changed `Merge.merge/1` to return diagnostic errors instead of raising for empty input.
- Changed recoverable failures from merge, text extraction, HTML rendering,
  pagination, PDF writing, and file operations to return
  `{:error, {reason, diagnostic}}` with `:stage`, `:reason`, `:message`,
  `:operation`, `:module`, and `:source` context when available.

## 0.4.0 - 2026-07-09

### Added

- Added a Chromium-backed browser parity test suite for the supported HTML/CSS rendering surface.
- Added browser parity fixtures for common layout, CSS cascade, tables, flexbox, grid, pagination, image, link, unit, and production-document scenarios.
- Added browser parity coverage documentation so supported renderer behavior is tied to explicit fixtures.

### Changed

- Improved HTML-to-PDF browser accuracy for nested table, flexbox, and grid compositions.
- Improved collapsed table border sizing and painting to better match browser output.
- Improved `@page` handling in parity tests so native and Chromium renders use the same page size and margins.
- Updated contribution guidance to require focused tests and browser parity coverage for visible HTML-to-PDF feature work.

### Fixed

- Fixed CSS custom property resolution inside supported compound values such as padding and side-specific borders.
- Fixed `box-sizing: border-box` handling across block, flex, grid, table, and image layout paths.
- Fixed table layout inside flex and grid items, and flex layout directly inside table cells.
- Fixed declared table row heights and pagination metadata propagation for table rows.
- Fixed pagination edge cases around first-page parent padding, overlapping parent/child groups, and zero-height metadata groups.

## 0.3.0 - 2026-07-08

### Added

- Added `NativeElixirPdfUtilities.HtmlToPdf`, a native HTML/CSS to PDF renderer for document-oriented templates.
- Added support for common document HTML including text, headings, paragraphs, spans, lists, links, tables, images, and nested document structure.
- Added support for common print-oriented CSS including cascade handling, box model sizing, text styling, borders, backgrounds, tables, flexbox, grid, page sizes, page breaks, and `@media print` behavior.
- Added embedded image, SVG rasterization, and custom TTF font rendering support for generated PDFs.
- Added multi-page pagination and PDF writing for rendered HTML documents.
- Added detailed render diagnostics for invalid HTML, unsupported HTML, invalid CSS, invalid layout, and invalid document failures.
- Added fixture coverage for purchase orders, material requisitions, stock stickers, and trim cards with realistic scrambled data.
- Added dedicated HTML-to-PDF compatibility and examples documentation.

### Changed

- Updated the package description to include native HTML/CSS rendering.
- Updated HexDocs metadata to include the HTML-to-PDF guides.

## 0.2.0 - 2026-07-03

### Added

- Added embedded text extraction so callers can consume readable text data from PDF binaries.

### Changed

- Refactored tokenizer, merge, and text internals to use explicit `case`/`cond` branching instead of guarded multi-head private functions.
- Split tests into focused tokenizer, merge, and text suites.
- Improved package documentation and HexDocs metadata for the release.

### Fixed

- Fixed page dictionary rewriting around empty arrays and MediaBox validation.
- Added 100% test coverage across the current public library modules.

## 0.1.0 - 2025-09-08

### Added

- Initial PDF tokenizer.
- Initial PDF merge utility.
