Текст: граница формирования, CJK и обработка прогонов
Модуль текста задаёт границу формирования. Он предоставляет небольшой интерфейс, который преобразует прогон в 8-битном формате преобразования Unicode (UTF-8) в позиционированные глифы, выбирает реальный бэкенд OpenType, если он доступен, детерминированно переходит на запасной вариант, если он недоступен, и предоставляет реестр шейперов для отдельных письменностей.
Установка
Заголовок раздела «Установка»composer require nextpdf/core:^3Концептуальный обзор
Заголовок раздела «Концептуальный обзор»ShaperInterface связывает конвейер компоновки текста с движком формирования OpenType. Он намеренно остаётся небольшим: один метод shape() принимает ShaperInput и возвращает ShapingResult. Возвращаемый тип — единственный результат, который видят потребители. Реализации не должны раскрывать внутреннее устройство движка формирования, а типизированный возврат обеспечивает соблюдение этой границы. ShapingResult содержит список записей GlyphRun, возвращённый исходный текст, письменность и направление, а также тег shaperImpl, который указывает, какой бэкенд создал результат.
Выбор бэкенда явный и сообщает о возможностях без догадок. ShaperFactory выполняет одну проверку возможностей. Если на хосте есть рабочая привязка HarfBuzz, create() возвращает шейпер на основе HarfBuzz. В противном случае он возвращает NullShaper. NullShaper — это сквозной запасной вариант. Он выдаёт один синтетический глиф на каждую кодовую точку Unicode с нулевыми приращениями и нулевыми смещениями. Он помечает результат тегом, чтобы средства наблюдаемости могли обнаружить запасной вариант, и оставляет вычисление приращений модулю метрик шрифтов. Этот путь — задокументированная деградация, а не полноценное формирование. Подстановка, лигатуры, позиционирование знаков и контекстные формы требуют реального бэкенда. wouldUseRealShaper() — диагностический предикат. Рабочий код должен вместо этого ветвиться по тегу shaperImpl в результате.
Формирование для отдельных письменностей — это интерфейс поставщика службы (SPI), а не встроенная реализация. ScriptShaperRegistry — это реестр по образцу PHP Standards Recommendation 11 (PSR-11), который разрешает MongolianShaperInterface или TibetanShaperInterface по тегу письменности International Organization for Standardization (ISO) 15924. Реестр хранит ключи без учёта регистра и в вопросе допустимости кодов письменностей опирается на единый источник истины. Реестр и интерфейсы шейперов письменностей — замороженный контракт, поэтому расширение может зарегистрировать поставщика Phase-12, не затрагивая места вызова. Движок предоставляет границу. Потребители предоставляют поставщиков для сложных письменностей.
Обработка прогонов на китайском, японском и корейском (CJK) находится на границе кодирования типографики. Встроенная гарнитура TrueType для CJK выводится как шрифт Type 0 с CMap Identity-H и потомком CIDFontType2, как это описано в ISO 32000-2 §9.7.4 (дайджест retrieval-augmented generation (RAG) усечён лицензионным ограничением; зафиксировано в _downgraded-claims-o3.md). Когда программа TrueType встроена, CIDFont типа Type 2 сопоставляет идентификаторы символов с индексами глифов через запись CIDToGIDMap, как это описано в ISO 32000-2 §9 (дайджест закреплён страницей контракта B1). Сабсеттер сохраняет исходную нумерацию глифов, поэтому /CIDToGIDMap /Identity остаётся допустимым для подмножества. CjkFontValidator проверяет, покрывает ли шрифт-кандидат блоки Unicode, необходимые для письменности, прежде чем этот шрифт будет выбран.
Поверхность API
Заголовок раздела «Поверхность API»| Тип | Вид | Основные члены | Стабильность | С версии |
|---|---|---|---|---|
ShaperInterface | interface | shape(ShaperInput): ShapingResult | стабильно | 3.2.0 |
ShaperFactory | final class | default(), create(), wouldUseRealShaper() | стабильно | 3.2.0 |
NullShaper | final readonly class | сквозной запасной шейпер | стабильно | 3.2.0 |
ShapingResult | final readonly class | $glyphRuns, $originalText, $script, $direction, $shaperImpl | стабильно | 3.2.0 |
ScriptShaperRegistry | final class | registerMongolian(), getMongolian(), hasMongolian() и тибетские эквиваленты | стабильно | 3.1.0 |
CjkFontValidator | final class | validateCoverage(), detectScript(), isCjkCodepoint() | стабильно | 1.0.0 |
Форма методов register*, get* и has* у ScriptShaperRegistry и интерфейсов шейперов письменностей — замороженный контракт. По замыслу ShapingResult остаётся единственным результатом шейпера, который видят потребители.
Пример кода — быстрый старт
Заголовок раздела «Пример кода — быстрый старт»<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Font\Shaper\ShaperFactory;use NextPDF\Font\Shaper\ShaperImpl;
$factory = ShaperFactory::default();$shaper = $factory->create();
// Branch on the result tag, not on the concrete class.$wouldShape = $factory->wouldUseRealShaper() ? 'HarfBuzz backend available' : 'NullShaper fallback (degraded — no substitution or positioning)';
echo $wouldShape, "\n";ShaperFactory::default() подключает рабочую проверку возможностей. create() запоминает выбранный бэкенд на всё время жизни фабрики. Используйте wouldUseRealShaper() и тег shaperImpl в каждом результате, чтобы проверять возможности.
Пример кода — рабочая среда
Заголовок раздела «Пример кода — рабочая среда»<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Text\Shaping\MongolianShaperInterface;use NextPDF\Text\Shaping\ScriptShaperRegistry;
final readonly class ComplexScriptBootstrap{ public function __construct(private ScriptShaperRegistry $registry) {}
/** * Register a consumer-supplied Mongolian shaper provider at boot so * the layout pipeline can resolve it by ISO 15924 script tag. */ public function register(MongolianShaperInterface $mongolian): void { $this->registry->registerMongolian($mongolian); }
public function hasMongolian(): bool { return $this->registry->hasMongolian(); }}Реестр — это точка интеграции для поставщиков сложных письменностей. Движок предоставляет границу и замороженную форму методов доступа. Потребители предоставляют монгольскую и тибетскую реализации.
Краевые случаи и подводные камни
Заголовок раздела «Краевые случаи и подводные камни»- Результат
NullShaperимеет нулевые приращения и нулевые смещения. Не передавайте эти позиции напрямую в компоновку текста. Вычисляйте приращения из модуля метрик шрифтов и обнаруживайте запасной вариант по тегуshaperImpl. - Пустой ввод даёт пустой список
glyphRuns, а не пустой прогон. Коду, который перебирает результат на стороне потребителя, не нужен отдельный случай для прогона нулевой длины. ScriptShaperRegistryне реализуетPsr\Container\ContainerInterfaceнапрямую, поэтому типизированные методы доступа сохраняют свой суженный возвращаемый тип при статическом анализе. ИспользуйтеgetMongolian()иgetTibetan(), а не обобщённыйget().- Теги письменностей сопоставляются по каноническому четырёхбуквенному значению ISO 15924 и хранятся без учёта регистра. Передайте
MongилиTibt. Регистр не влияет на поиск. - Символы CJK Extension B находятся в плоскости 2 Unicode и требуют подтаблицы cmap Format 12 в подмножестве. Путь кодирования обрабатывает это. Не предполагайте, что базовая многоязычная плоскость покрывает весь текст CJK.
Производительность
Заголовок раздела «Производительность»Проверка возможностей выполняется один раз на экземпляр ShaperFactory, а бэкенд запоминается, поэтому повторные вызовы create() бесплатны. NullShaper линеен по количеству кодовых точек во входном прогоне и не выполняет операций input/output (I/O). Разрешение ScriptShaperRegistry — это поиск по ключу за постоянное время. CjkFontValidator выбирает кодовые точки с шагом, а не проверяет каждую, поэтому проверка покрытия остаётся недорогой даже для шрифта CJK с 20,000 глифами. performance_budget в 1500 мс реального времени и 64 МБ пикового использования покрывает типичный запуск. При реальном формировании основные затраты приходятся на бэкенд OpenType. Когда активен запасной вариант, эти затраты находятся вне области действия этого модуля.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»Граница шейпера принимает строку UTF-8. NullShaper терпимо относится к некорректному UTF-8: разбивает его по мере возможности вместо выбрасывания исключения, поскольку задокументированный контракт запасного варианта уже подразумевает «отсутствие настоящего формирования». Вызывающая сторона уже готова к выводу низкого качества. Контракт кластеров по байтовым смещениям использует длину в байтах, что корректно для многобайтового ввода и помогает избежать ошибки сопоставления кластеров со сдвигом на кодовую точку. Когда настоящий бэкенд присутствует, это сторонняя нативная библиотека. Считайте его ввод недоверенным и ограничивайте длину прогона выше по конвейеру. Реестр шейперов письменностей хранит поставщиков, предоставленных потребителем. Эти реализации находятся внутри границы доверия потребителя, а не движка.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Стандарт | Пункт | Свидетельство |
|---|---|---|---|
Встроенная гарнитура TrueType для CJK выводится как шрифт Type 0 с CMap Identity-H и потомком CIDFontType2. | ISO 32000-2 | §9.7.4 | Дайджест retrieval-augmented generation (RAG) усечён лицензионным ограничением; префикс 7a5258772f508e3b, см. _downgraded-claims-o3.md |
Встроенный CIDFont типа Type 2 сопоставляет идентификаторы символов с индексами глифов через CIDToGIDMap. | ISO 32000-2 | §9 |
Оба пункта изложены в пересказе. Второй закреплён дайджестом (повторно используется со страницы контракта B1), а первый подтверждается ADR-013 и обзором cmap-кодировщика для разработчиков. NextPDF не воспроизводит нормативный текст. Бэкенд шейпера не зависит от соответствия Portable Document Format (PDF). Утверждения о соответствии здесь касаются вывода словаря шрифтов CJK, создаваемого границей кодирования. ADR-013 и обзор cmap-кодировщика для разработчиков документируют этот путь подробнее.
Коммерческий контекст
Заголовок раздела «Коммерческий контекст»Расширенный конвейер предобработки текста и службы извлечения строятся на границе шейпера Core и типах-значениях обработки прогонов. Модуль текста Core предоставляет границу, запасной вариант и реестр шейперов письменностей без лицензии. Отсутствие ссылки на конверсию сделано намеренно.
См. также
Заголовок раздела «См. также»- Типографика: реестр, формирование подмножеств, CMap, кодирование, BiDi — граница кодирования и движок двунаправленного текста.
- Шрифт: типы-значения, встраивание, запасной вариант — значение
FontInfo, на которое ссылается ввод шейпера. - Контракты / Типографика — контракт препроцессора текста выше по конвейеру относительно формирования.