HTML: sottosistema di rendering da HTML+CSS verso PDF
In breve
Sezione intitolata “In breve”Il sottosistema HTML converte HTML+CSS in flussi di contenuto PDF con un’unica passata in avanti. È il sottosistema più esteso e a più alto rischio del motore (324 file in src/Html/).
Installazione
Sezione intitolata “Installazione”composer require nextpdf/core:^3Panoramica concettuale
Sezione intitolata “Panoramica concettuale”Il sottosistema HTML è un renderer streaming a passata singola da HTML+CSS verso PDF. La superficie pubblica espone un solo metodo, Document::writeHtml(). Internamente, HtmlParser tokenizza l’input, risolve gli stili, calcola l’impaginazione ed emette operatori PDF in un’unica passata in avanti, senza conservare un albero del documento.
È importante chiarire l’ambito. Questo sottosistema non è un renderer a documento ritenuto. Non mantiene un grafo degli elementi, non rielabora l’impaginazione dei contenuti già scritti e non consente di modificare l’input dopo l’avvio dell’analisi. Implementa un sottoinsieme curato di CSS con versioni di specifica fissate. Due decisioni architetturali lo governano. ADR-001 fissa il modello di streaming a passata singola e i relativi limiti. ADR-010 fissa il contratto a quattro livelli (analisi CSS, stato di stile, impaginazione, paint), insieme alle componenti aggiuntive per i media paginati e per la misurazione.
HtmlParser ha un livello di rischio classificato come critico nel manifest del modulo. Cinque file riportano annotazioni documentate come zona pericolosa: l’orchestratore HtmlParser (tokenizer in streaming, oltre 1000 LOC), HtmlStyleState (oltre 100 campi di proprietà CSS con un modello di ereditarietà a stack), HtmlBlockHandler (dispatch dei blocchi accoppiato allo stato di stile), FlexLayoutEngine (misurazione e impaginazione flex complete) e TableParser (paginazione colspan/rowspan attraverso le interruzioni di pagina). Trattare le modifiche in quest’area come lavoro in modalità di pianificazione.
Questa pagina è il punto di ingresso. Le pagine di dettaglio coprono: pipeline per la sequenza delle fasi, css-resolver per cascata e specificità, layer-contracts-adr010 per i confini tra i livelli e streaming-constraints-adr001 per il modello senza albero ritenuto e i relativi limiti.
Testo da destra a sinistra e bidirezionale
Sezione intitolata “Testo da destra a sinistra e bidirezionale”writeHtml() esegue il rendering di contenuti da destra a sinistra (RTL). Impostare la proprietà CSS direction: rtl sul body, su una tabella o su qualsiasi elemento. Il motore risolve l’ordine visivo con l’algoritmo bidirezionale Unicode (UAX #9) tramite il motore bidirezionale del livello di tipografia — vedere Tipografia per i dettagli su BidiEngine. I contenuti misti latini, arabi e numerici vengono ordinati correttamente e un numero che segue l’arabo mantiene le sue cifre da sinistra a destra.
Anche l’arabo riceve lo shaping contestuale: il motore seleziona la forma iniziale, mediale, finale o isolata di ciascuna lettera e applica la legatura Lam-Alef. Lo shaping richiede un font registrato la cui character map copra il blocco Arabic Presentation Forms-B; una face solo latina, inclusi i font standard-14, non può disegnare l’arabo. Nelle tabelle, ogni cella viene riordinata e sottoposta a shaping autonomamente e si allinea al lato iniziale (destro) con direction: rtl. L’RTL si applica ad arabo, ebraico, persiano e urdu; l’ebraico viene riordinato ma non sottoposto a shaping.
Impostare la direzione con la proprietà CSS direction — l’attributo HTML dir non viene mappato su di essa. L’allineamento orizzontale del testo di blocco e inline non di tabella, e text-align: justify, non sono ancora applicati. Per una fattura araba eseguibile e l’elenco completo delle limitazioni attuali, vedere Eseguire il rendering di HTML arabo da destra a sinistra.
Superficie API
Sezione intitolata “Superficie API”| Simbolo | Posizione | Ruolo |
|---|---|---|
Document::writeHtml(string $html): static | src/Core/Concerns/HasTextOutput.php | Punto di ingresso pubblico. Esegue il rendering dell’HTML alla posizione corrente del cursore. |
Document::createStandalone(): self | src/Core/Document.php | Crea un documento autonomo. |
HtmlParser::parse(string $html): HtmlRenderResult | src/Html/HtmlParser.php | Orchestratore interno. |
HtmlRenderResult | src/Html/HtmlRenderResult.php | Risultato immutabile: flusso, cursore finale, font utilizzati. |
DefaultHtmlSecurityPolicy | src/Html/DefaultHtmlSecurityPolicy.php | Criteri predefiniti per tag/attributi/CSS/URL. |
HtmlSecurityPolicyInterface | src/Contracts/HtmlSecurityPolicyInterface.php | Contratto per i criteri personalizzati. |
Esempio di codice — Avvio rapido
Sezione intitolata “Esempio di codice — Avvio rapido”Tratto da examples/08-html-basic.php.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('HTML Basic');$doc->addPage();$doc->writeHtml('<h1 style="color:#1E3A8A;">HTML Rendering</h1><p>Direct to PDF.</p>');$doc->save(__DIR__ . '/output/08-html-basic.pdf');Esempio di codice — Produzione
Sezione intitolata “Esempio di codice — Produzione”Un report tabellare con un blocco di stile incorporato, modellato su examples/09-html-table.php.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Exception\HtmlParsingException;
function renderInventory(string $rowsHtml, string $out): void{ $doc = Document::createStandalone(); $doc->setTitle('Inventory'); $doc->addPage();
$html = '<style>table { width: 100%; } ' . 'th { background-color: #1E3A8A; color: #FFFFFF; }</style>' . '<table border="1" cellpadding="5">' . $rowsHtml . '</table>';
try { $doc->writeHtml($html); } catch (HtmlParsingException $e) { // Input cap, element cap (50,000), or nesting cap (100). Do not retry. throw $e; }
$doc->save($out);}Casi limite e insidie
Sezione intitolata “Casi limite e insidie”- Sottoinsieme CSS curato. Il supporto è definito per modulo e per versione fissata. Consultare la matrice di supporto CSS prima di fare affidamento su una proprietà.
- I limiti rigidi generano eccezioni. Input di 10 MB,
50,000elementi, 100 livelli di annidamento: ciascuno generaHtmlParsingException. Vedere vincoli dello streaming. - Nessuna rielaborazione dell’impaginazione. L’output viene scritto una sola volta nell’ordine del documento; gli stili successivi non possono modificare l’output già prodotto.
:has()è subordinato alla funzionalità sperimentalecss.has.- Sottosistema a rischio critico. Cinque file sono contrassegnati come zona pericolosa. Usare la modalità di pianificazione per le modifiche in
src/Html/.
Vincoli dello streaming a passata singola (ADR-001)
Sezione intitolata “Vincoli dello streaming a passata singola (ADR-001)”Il renderer non mantiene alcun albero del documento ed esegue un’unica passata in avanti. I limiti su elementi, annidamento e input sono rigidi. I dettagli completi e il contratto di sicurezza per i worker si trovano in vincoli dello streaming (ADR-001).
Contratti tra livelli (ADR-010)
Sezione intitolata “Contratti tra livelli (ADR-010)”L’analisi CSS, lo stato di stile, l’impaginazione e il paint sono separati in quattro livelli con contratti unidirezionali, insieme alle componenti aggiuntive per i media paginati e per la misurazione. Dettagli completi in contratti tra livelli (ADR-010).
Budget di memoria per documenti di grandi dimensioni
Sezione intitolata “Budget di memoria per documenti di grandi dimensioni”La memoria per lo stato di stile e il cursore è O(profondità di annidamento), non O(numero di elementi). Il performance_budget per pagina è peak_mb: 64. Il limite di 50,000 elementi rappresenta il tetto massimo; suddividere gli input più grandi su più chiamate writeHtml(). Dettagli in vincoli dello streaming.
Prestazioni
Sezione intitolata “Prestazioni”L’attraversamento è O(numero di token). Il dimensionamento delle colonne delle tabelle aggiunge una scansione limitata delle righe per ogni tabella. La pre-scansione opzionale :has() aggiunge una passata limitata sull’elenco dei token. Il benchmark delle prestazioni della pipeline di rendering HTML applica una soglia di regressione del 5% (lavoro già integrato, PR #564). Il performance_budget per pagina (wall_ms: 1500, peak_mb: 64) è il tetto operativo.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”DefaultHtmlSecurityPolicy applica una allowlist di tag, attributi, proprietà CSS e schemi URL, oltre a un tetto di input di 10 MB e a un tetto di annidamento di 100 livelli, indipendentemente dal parser. L’allowlist delle proprietà CSS è il tetto di sicurezza. La tabella di supporto a runtime è un tetto di funzionalità distinto. Implementare HtmlSecurityPolicyInterface per fornire criteri più restrittivi. Il recupero delle risorse esterne è regolato separatamente da DefaultExternalResourcePolicy.
Nei valori href e src delle immagini, l’allowlist degli URL rifiuta anche i percorsi con radice backslash (\…) e UNC (\\host\share), oltre al rifiuto già esistente dei percorsi protocol-relative (//) e all’allowlist che ammette solo http(s) o percorsi relativi. I backslash vengono normalizzati in slash prima del controllo, quindi un include di file locale con percorso assoluto Windows o un recupero da condivisione SMB — nessuno dei quali presenta uno schema URI — non può sfuggire attraverso il ramo “nessuno schema, quindi relativo”.
Estratto della matrice di supporto CSS (solo righe verificate)
Sezione intitolata “Estratto della matrice di supporto CSS (solo righe verificate)”Questa pagina non ripete il supporto proprietà per proprietà. La matrice di supporto CSS è l’unico riferimento autorevole per lo stato verificato per modulo W3C, inclusi i moduli verificati e quelli dichiarati.
Conformità
Sezione intitolata “Conformità”Il sottosistema implementa un sottoinsieme curato di CSS con versioni di specifica fissate. Le mappature comportamentali della specifica per la cascata sono documentate con identificatori di clausola e chunk in css-resolver. Lo stato di conformità per modulo è disponibile nella matrice di supporto CSS.
Contesto commerciale
Sezione intitolata “Contesto commerciale”Funzionalità Enterprise. Premium amplia la copertura CSS (stampa avanzata e moduli aggiuntivi) sulla stessa identica pipeline a passata singola. L’architettura, i limiti e i contratti tra livelli sono identici in tutte le edizioni. Vedere la matrice di supporto CSS.