pdg
Декларативный документ на входе, разбитый на страницы PDF на выходе.
Движок вёрстки, превращающий небольшой декларативный 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.