Pro редакция
Flow Layout — глубокий справочник
Эта страница — глубокий справочник по модулю Pro Flow Layout. Она охватывает движок размещения, модель элемента, стратегии разрыва страниц, их контракты поведения и режимы отказа. StreamingLayoutEngine обходит список значений FlowElement по порядку. Каждому он назначает отсчитываемый от нуля индекс страницы и позицию внутри LayoutRegion. Результат — LayoutResult из неизменяемых записей PlacedElement. Модуль только вычисляет размещение; он ничего не рендерит и не выполняет ввод-вывод.
Доступность и лицензирование
Заголовок раздела «Доступность и лицензирование»Эта возможность поставляется в составе NextPDF Pro (nextpdf/pro) и активируется лицензионным конвертом уровня Pro. Развёртывание без этого права доступа не загружает классы возможности. Сравнить редакции и получить лицензию.
Отдельного лицензионного флага для этой возможности нет. Это возможность редакции Pro.
Публичная поверхность API
Заголовок раздела «Публичная поверхность API»Все символы находятся в пространстве имён NextPDF\Pro\FlowLayout. Все объекты-значения объявлены final и неизменяемы.
| Символ | Параметры | Поведение по умолчанию | Возвращает | Бросает или завершается с | Примечания |
|---|---|---|---|---|---|
StreamingLayoutEngine::__construct | LayoutRegion $region, PageBreakStrategy $strategy = PageBreakStrategy::Greedy | Связывает область содержимого каждой страницы со стратегией разрыва | StreamingLayoutEngine | — | По умолчанию стратегия Greedy. |
StreamingLayoutEngine::layout | list<FlowElement> $elements | Один прямой проход; последовательное размещение с разрывами страниц по стратегии | LayoutResult | Никогда не бросает | Пустой список даёт одну пустую страницу. |
StreamingLayoutEngine::withStrategy | PageBreakStrategy $strategy | Порождает новый движок с той же областью | self | — | Получатель не изменяется. |
StreamingLayoutEngine::withRegion | LayoutRegion $region | Порождает новый движок с той же стратегией | self | — | Получатель не изменяется. |
FlowElement::__construct | FlowElementType $type, string $content, float $widthPt = 0, float $heightPt = 0, float $marginTopPt = 0, float $marginBottomPt = 0, bool $keepWithNext = false | Неизменяемый объект-значение элемента | FlowElement | — | Единственный способ создания элементов Table. |
FlowElement::text | string $content, float $height | Текстовый элемент с высотой, измеренной вызывающей стороной | self (статический) | — | Ширина 0 разрешается в ширину области при размещении. |
FlowElement::image | string $path, float $width, float $height | Элемент изображения; content содержит путь | self (статический) | — | Движок никогда не открывает файл. |
FlowElement::spacer | float $height | Вертикальный пробел с пустым содержимым | self (статический) | — | — |
FlowElement::pageBreak | — | Явный маркер разрыва | self (статический) | — | Не создаёт PlacedElement. |
FlowElement::totalHeight | — | Высота плюс верхний и нижний отступы | float | — | Все проверки помещаемости используют это значение. |
FlowElementType | варианты перечисления Text, Image, Table, Spacer, PageBreak | На основе строк: text, image, table, spacer, page_break | — | — | — |
FlowElementType::isBreakable | — | Text и Table возвращают true; остальные — false | bool | — | Только классификация; см. контракт атомарного размещения ниже. |
LayoutRegion::__construct | float $x, float $y, float $width, float $height | Прямоугольник содержимого с началом в левом верхнем углу, в пунктах | LayoutRegion | — | Без проверки; значения берутся как есть. |
LayoutRegion::contains | float $px, float $py | Проверка попадания точки в область, включая границу | bool | — | — |
LayoutRegion::remainingHeight | float $currentY | Высота области минус израсходованное вертикальное смещение | float | — | Ноль или отрицательное значение после переполнения курсора. |
LayoutResult::__construct | list<PlacedElement> $placements, int $pageCount, float $totalHeightPt | Неизменяемый результат размещения | LayoutResult | — | — |
LayoutResult::placementsOnPage | int $pageIndex | Фильтрует размещения по отсчитываемому от нуля индексу страницы | list<PlacedElement> | — | Возвращаемый список переиндексируется. |
LayoutResult::isEmpty | — | true, когда ни один элемент не размещён | bool | — | true для пустого ввода и ввода только из разрывов. |
PageBreakStrategy | варианты перечисления Greedy, AvoidOrphans, KeepTogether | На основе строк: greedy, avoid_orphans, keep_together | — | — | — |
PageBreakStrategy::label | — | Человекочитаемая метка стратегии | string | — | — |
PlacedElement::__construct | FlowElement $element, int $pageIndex, float $x, float $y, float $width, float $height | Неизменяемая запись размещения | PlacedElement | — | Координаты в пунктах, начало в левом верхнем углу. |
public function layout(array $elements): LayoutResultpublic function withStrategy(PageBreakStrategy $strategy): selfpublic function withRegion(LayoutRegion $region): selfpublic static function text(string $content, float $height): selfpublic static function image(string $path, float $width, float $height): selfpublic static function spacer(float $height): selfpublic static function pageBreak(): selfКонтракт поведения
Заголовок раздела «Контракт поведения»StreamingLayoutEngine::layout() выполняет один прямой проход по входному списку. Для каждого элемента он проверяет помещаемость, при необходимости разрывает страницу, затем записывает PlacedElement. Пустой входной список возвращает LayoutResult без размещений, с числом страниц 1 и общей высотой 0.
Геометрия размещения детерминирована:
x— левый край области.y— текущая позиция курсора плюс верхний отступ элемента.width—widthPtэлемента, если он положителен, иначе ширина области.height—heightPtэлемента, ровно как передано.
После каждого размещения курсор смещается на totalHeight(), включая отступы. Та же величина накапливается в LayoutResult::totalHeightPt.
Правила разрыва страниц, в порядке проверки:
- Явный элемент
PageBreakувеличивает индекс страницы и сбрасывает курсор к верху области. Он не создаёт размещения и ничего не добавляет к общей высоте. - Когда
totalHeight()элемента превышает оставшуюся высоту, движок разрывает страницу — если только курсор уже не находится в верху страницы. Greedyне добавляет дополнительных условий: помещающиеся элементы всегда размещаются.AvoidOrphansразрывает страницу перед помещающимся элементом, когда пространство, остающееся после размещения, было бы положительным, но меньше половины собственной требуемой высоты элемента. Опорной единицей служит собственная высота элемента с фиксированным делителем два; никакие метрики шрифта не участвуют. Он никогда не разрывает в верху страницы.KeepTogetherразрывает страницу перед помещающимся элементом, когда установлен его флагkeepWithNext, существует следующий элемент, курсор не в верху страницы и суммарнаяtotalHeight()обоих элементов превышает оставшееся пространство. Флаг на последнем элементе не действует.
Атомарное размещение: движок размещает каждый элемент как единое целое. Он никогда не разбивает содержимое элемента между страницами. FlowElementType::isBreakable() классифицирует, какие типы вызывающая сторона может заранее разбить на меньшие элементы; сам движок к нему не обращается.
Отсутствие состояния и детерминизм: движок хранит только свою область и стратегию. layout() не разделяет состояние между вызовами, и одинаковые входные данные дают одинаковые результаты. withStrategy() и withRegion() возвращают новые движки и никогда не изменяют получателя.
Граничные случаи и режимы отказа
Заголовок раздела «Граничные случаи и режимы отказа»- Ни один метод этого модуля не бросает исключений. Нет иерархии исключений, которую нужно перехватывать.
- Конструкторы ничего не проверяют. Отрицательные или нулевые размеры области, отрицательные высоты элементов и отрицательные отступы принимаются и проходят через арифметику без изменений.
- Элемент выше области всё равно размещается. В верху страницы он размещается там и выходит за пределы; в другом месте движок сначала разрывает страницу, и элемент выходит за пределы новой страницы. Следующий элемент затем всегда вызывает разрыв, поэтому переполнение ограничено одной страницей.
- Ведущий
PageBreakразмещает первый содержательный элемент на странице с индексом 1, давая число страниц не менее 2. - Последовательные элементы
PageBreakкаждый увеличивают счётчик страниц, создавая пустые страницы. Завершающий оставляет вpageCountпоследнюю пустую страницу. - Keep-together действует только тогда, когда оба парных элемента помещаются на одной странице вместе. Пара, суммарная высота которой превышает целую страницу, всё же разбивается.
- Неположительный
widthPtразрешается в ширину области; проверка подстановки — строго больше нуля. remainingHeight()может вернуть ноль или отрицательное значение после переполнения курсора.contains()считает границу области находящейся внутри.placementsOnPage()с индексом вне диапазона возвращает пустой список.- Этот модуль не выполняет криптографических операций и не определяет специфичного для FIPS поведения.
Соответствие
Заголовок раздела «Соответствие»Flow Layout реализует поведение размещения, определённое NextPDF. Он не нацелен на внешний стандарт макета или типографики, поэтому на этой странице нет нормативной таблицы цитирования. Стратегии разрыва страниц — это семантика NextPDF; они не являются реализациями свойств фрагментации CSS или какой-либо модели keep из XSL-FO. Все размеры выражены в пунктах, что соответствует единицам, которые потребляет модуль записи Core.
Эти утверждения описывают только возможности. NextPDF не имеет сертификации соответствия, и никакое заявление о сертификации не делается и не подразумевается.
Заметки для разработки
Заголовок раздела «Заметки для разработки»- Измеряйте содержимое заранее. Движок потребляет высоты, переданные вызывающей стороной; у него нет метрик шрифта, и он не измеряет текст.
- Заранее разбивайте длинный текст или содержимое таблиц на несколько элементов до размещения. Используйте
isBreakable(), чтобы решить, какие типы может разбивать разбивщик. - Повторно используйте один движок на каждую геометрию страницы. Дёшево порождайте варианты с помощью
withStrategy()иwithRegion(). - Группируйте вывод по страницам с помощью
placementsOnPage()при постраничном рендеринге. - Размещение — это один проход, линейный по числу элементов, и не хранит дерево документа. Результаты детерминированы, что подходит для тестов на золотых файлах.
- Для рендеринга HTML в PDF используйте вместо этого конвейер Core HTML; этот модуль не является движком HTML или CSS.
Граница публикации
Заголовок раздела «Граница публикации»Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую публичную поверхность API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов runbook и префиксы тикетов — вне области рассмотрения.