Pular para o conteúdo
getnextpdf.com

estabilidade: Experimental

Suporte a composição de scripts complexos

Pré-visualização opcional. A composição de scripts complexos é desativada por padrão. Quando está desativada, o motor renderiza pelo caminho existente de codepoint para cmap — idêntico byte a byte à de uma compilação sem o recurso. Ative-a somente quando você tiver o libharfbuzz e uma fonte capaz de composição, e valide o resultado.

O renderizador HTML adiciona um compositor de scripts complexos opcional para tibetano e mongol. Quando o compositor está ativado, uma sequência em tibetano ou mongol detectada no escopo é composta através do libharfbuzz e emitida como códigos de glifo Identity-H. O compositor cobre tibetano horizontal em faces TrueType e CFF/OTTO, incluindo quebra de linha, e mongol vertical disposto de cima para baixo (TTB).

Terminal window
composer require nextpdf/core:^3

O compositor é entregue no pacote core. O recurso opcional CssFeatureFlags::$complexTextShaping é @since 6.1.0. O libharfbuzz é um requisito de runtime quando a flag está ativada — o compositor chama o libharfbuzz através da extensão FFI do PHP. Quando a flag está desativada, a biblioteca não tem dependência de libharfbuzz.

Scripts complexos reordenam, substituem e reposicionam glifos conforme o contexto. Um mapeamento ingênuo de codepoint para glifo os renderiza visivelmente errados. O compositor entrega uma sequência no escopo ao libharfbuzz, que aplica as tabelas de composição OpenType da fonte, e o motor emite a sequência de glifos resultante como uma fonte composta Type 0 com codificação Identity-H (ISO 32000-2 §9.7.4 — a string exibida é de CIDs de dois bytes).

O escopo é deliberado. O compositor reconhece sequências em tibetano e mongol e as compõe; ele não reivindica cobertura geral de scripts complexos. O tibetano horizontal é composto em faces TrueType e CFF/OTTO, com quebra de linha. O mongol é composto verticalmente, de cima para baixo.

O compositor nunca emite glifos não compostos e visualmente quebrados como fallback. Uma sequência que não pode ser composta fielmente levanta uma exceção tipada em vez disso:

  • ComplexScriptShapingException — a sequência não pode ser composta fielmente: a fonte não tem os glifos necessários (resultaria um .notdef), pede-se a uma face CFF que componha no caminho vertical, a sequência contém um link ou uma coluna mongol precisa de quebra de linha (um caso fora do escopo).
  • HarfBuzzUnavailableException — a flag está ativada, mas o libharfbuzz não é alcançável por FFI em runtime.

Com a flag desativada, uma sequência no escopo é renderizada pelo caminho existente de codepoint para cmap. Essa é uma limitação documentada, não uma reivindicação de composição: o caminho desativado não aplica composição OpenType, então as formas contextuais não são garantidas. Não descreva a saída do caminho desativado como “composta”.

Limite de honestidade — paridade objetiva, não aval estético

Seção intitulada “Limite de honestidade — paridade objetiva, não aval estético”

A fidelidade de composição é validada objetivamente contra o HarfBuzz: os identificadores de glifo emitidos, o mapeamento de cluster e as posições de glifo correspondem à saída de referência do HarfBuzz (paridade de glifo, cluster e posição). Uma revisão estética por falante nativo — julgando se o resultado é lido naturalmente por um leitor fluente — é um acompanhamento pós-lançamento rastreado. O NextPDF não faz nenhuma reivindicação de qualidade de idioma nesta API nem nesta documentação. A paridade objetiva é afirmada; a qualidade estética não.

SímboloLocalizaçãoFunção
CssFeatureFlags::$complexTextShapingsrc/Html/CssFeatureFlags.phpFlag opcional para o compositor de tibetano/mongol (padrão false).
Config::withCssFeatureFlags(CssFeatureFlags $flags): selfsrc/Core/Config.phpAnexa o conjunto de flags a uma configuração de documento.
ComplexScriptShapingExceptionsrc/Font/Shaper/ComplexScriptShapingException.phpLançada quando uma sequência no escopo não pode ser composta fielmente.
HarfBuzzUnavailableExceptionsrc/Font/Shaper/HarfBuzzUnavailableException.phpLançada quando a flag está ativada, mas o libharfbuzz está indisponível.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Config;
use NextPDF\Core\Document;
use NextPDF\Html\Css\CssFeatureFlags;
$config = (new Config())->withCssFeatureFlags(
new CssFeatureFlags(complexTextShaping: true),
);
$doc = Document::createStandalone($config);
$doc->addPage();
$doc->writeHtml(
'<div style="font-family: NotoSerifTibetan;">བོད་སྐད་</div>',
);
$doc->save(__DIR__ . '/tibetan.pdf');

Registre uma fonte capaz de composição, opte pelo compositor e trate os dois modos de falha tipados explicitamente. Uma renderização fiel ou uma exceção clara — nunca uma sequência de glifos silenciosamente quebrada.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Config;
use NextPDF\Core\DocumentFactory;
use NextPDF\Exception\ComplexScriptShapingException;
use NextPDF\Exception\HarfBuzzUnavailableException;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Html\Css\CssFeatureFlags;
use NextPDF\Typography\FontRegistry;
$fontRegistry = new FontRegistry();
$fontRegistry->register('/path/to/NotoSerifTibetan-Regular.ttf', alias: 'NotoSerifTibetan');
$config = (new Config())->withCssFeatureFlags(
new CssFeatureFlags(complexTextShaping: true),
);
$factory = new DocumentFactory($fontRegistry, new ImageRegistry(maxCacheBytes: 0));
$doc = $factory->create($config);
$doc->setLanguage('bo');
$doc->addPage();
try {
$doc->writeHtml('<div style="font-family: NotoSerifTibetan;">བོད་སྐད་</div>');
} catch (HarfBuzzUnavailableException $e) {
// The flag is on but libharfbuzz is not reachable. Install it, or turn the
// flag off to fall back to the unshaped cmap path.
throw $e;
} catch (ComplexScriptShapingException $e) {
// The run cannot be shaped faithfully (missing glyphs, link in run,
// out-of-scope case). Fix the font or the content; do not ship broken glyphs.
throw $e;
}
$doc->save($out);
  • O libharfbuzz é obrigatório quando ativado. Com a flag ativada e o libharfbuzz ausente, o motor lança HarfBuzzUnavailableException. Ele não degrada silenciosamente.
  • Desativado não é “composto”. Com a flag desativada, uma sequência no escopo é renderizada pelo caminho de cmap sem composição OpenType. Essa é uma limitação documentada; não a chame de saída composta.
  • O escopo é tibetano e mongol. Outros scripts complexos estão fora do escopo desta fatia.
  • Um link na sequência falha fechado. Uma sequência que contém uma anotação de link levanta ComplexScriptShapingException, porque o retângulo do link não pode acompanhar a reordenação composta.
  • Nenhuma reivindicação de qualidade de idioma. A paridade com o HarfBuzz é afirmada; a qualidade estética por falante nativo é um acompanhamento rastreado e não é reivindicada.

A composição adiciona uma chamada ao libharfbuzz por sequência no escopo, mais a passada de emissão de glifos, linear na contagem de glifos. O orçamento (wall_ms: 2000, peak_mb: 128) segue o perfil CJK/scripts complexos, porque as fontes de composição são grandes e o manuseio de fonte domina o custo.

Ativar o compositor introduz uma chamada FFI para o libharfbuzz, uma biblioteca nativa. Os arquivos de fonte permanecem como entrada binária não confiável tratada pela validação existente da camada de tipografia antes de chegarem ao compositor. O compositor consome faces já registradas e já validadas. Trate a procedência de fontes fornecidas por usuário final como não confiável e provisione o libharfbuzz a partir de uma fonte confiável.

DeclaraçãoEspecificaçãoCláusula
Sequências compostas são emitidas como CIDs de dois bytes Identity-H em uma fonte composta Type 0.ISO 32000-2§9.7.4
O compositor aplica a substituição e o posicionamento de glifos OpenType da fonte.OpenType SpecificationGSUB / GPOS
A formação de clusters segue as propriedades de script para tibetano e mongol.Unicode Standard AnnexTibetan and Mongolian

Esta é uma implementação de pré-visualização limitada a tibetano e mongol, validada quanto à paridade objetiva com o HarfBuzz. Ela não faz nenhuma reivindicação de qualidade de idioma e não afirma nenhuma conformidade PDF de ponta a ponta para o arquivo produzido. Nenhum texto de norma é reproduzido.