pdg

Декларативный документ на входе, разбитый на страницы PDF на выходе.

Знак pdg — свёрстанная страница с красным заголовком и серыми строками текста на тёмной скруглённой плитке, по центру кремового фона, разлинованного как гранка

Движок вёрстки, превращающий небольшой декларативный XML-документ в готовый к печати PDF. Вы описываете, что на странице — заголовки, таблицы, колонки, линейки, — а pdg решает, где это окажется: переносит текст, вкладывает контейнеры и разбивает на страницы всё, что не поместилось.

Весь движок держится на одном вопросе. Каждый элемент спрашивают: вот столько места — сколько тебя поместится? — и он отвечает одним из трёх способов: помещается целиком, помещается частично (возвращая остаток, чтобы продолжить на новой странице) или не помещается вовсе. Применённый рекурсивно, этот единственный протокол и даёт перенос текста, вложенную вёрстку и многостраничный поток — ни одно из этого не частный случай. Заголовок таблицы повторяется на каждой странице, а слишком высокая строка разрывается на границе именно поэтому, а не потому, что таблицы отдельно научили про страницы. Разбор, вёрстка, пагинация и рендер — отдельные стадии, а PDF спрятан за feature-флагом по ту сторону IR из позиционированных примитивов: вёрстка про PDF не знает ничего.

Словарь остаётся маленьким: text с инлайновой разметкой, vertical / horizontal как один flex-подобный движок, box, table, list, stack — и атрибуты style:, несущие блочную модель на любом элементе. Блок <layout> — шаблон страницы, повторяемый на каждой физической странице, включая те, что создаёт пагинация; <defaults> задаёт умолчания по тегам и действует позиционно, на тех соседей, что идут после него; <pdf> подмешивает страницы из внешнего файла.

Жить с этим помогают две вещи. debug="true" на любом элементе — инспектор вёрстки в духе браузерных devtools: рамки, зазоры, поля и отступы, нарисованные поверх и не сдвигающие то, что измеряют. И движок никогда не падает: неизвестный тег пропускается, кривая длина берётся по умолчанию — и каждое такое молчаливое восстановление докладывается диагностикой с line:col и трассой объемлющих тегов — стек-трейсом внутрь вашего документа; строгий режим заставляет ошибки блокировать вывод.

Шрифты встраиваются и сабсетятся до использованных глифов — поэтому кириллица рендерится, а файлы остаются лёгкими; 14 стандартных PDF-гарнитур подключаются ссылкой и весят ноль байт. А раз документ — это просто разметка, писать его может damask: компонент рендерит XML для pdg на этапе компиляции, и PDF получается из тех же типизированных, проверенных компилятором шаблонов, что и веб-страница, — структура на входе, PDF на выходе, одна cargo build. Rust, а плейграунд — тот же движок, собранный в WebAssembly: браузер показывает ровно тот PDF, который пишет CLI.