HTML : sous-système de rendu HTML+CSS vers PDF
En un coup d’œil
Section intitulée « En un coup d’œil »Le sous-système HTML convertit HTML+CSS en flux de contenu PDF en une seule passe, dans l’ordre d’entrée. C’est le sous-système le plus volumineux et le plus risqué du moteur (324 fichiers sous src/Html/).
Installation
Section intitulée « Installation »composer require nextpdf/core:^3Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »Le sous-système HTML est un moteur de rendu HTML+CSS vers PDF en flux à passe unique. Sa surface publique se limite à une seule méthode, Document::writeHtml(). En interne, HtmlParser découpe l’entrée en tokens, résout les styles, calcule la mise en page et émet les opérateurs PDF en une seule passe, dans l’ordre d’entrée, sans conserver d’arbre de document.
Sois clair sur le périmètre. Ce sous-système n’est pas un moteur de rendu à document conservé. Il ne conserve aucun graphe d’éléments, ne refait pas la mise en page d’un contenu déjà écrit et n’autorise pas l’entrée à muter une fois l’analyse commencée. Il implémente un sous-ensemble CSS sélectionné, figé sur des versions de spécification fixes. Deux décisions d’architecture l’encadrent. ADR-001 fige le modèle de flux à passe unique et ses plafonds. ADR-010 fige le contrat à quatre couches (analyse CSS, état de style, mise en page, peinture) ainsi que les ajouts de média paginé et de mesure.
HtmlParser est classé comme risque critique dans le manifeste du module. Cinq fichiers portent des annotations documentées de zone dangereuse : l’orchestrateur HtmlParser (tokeniseur en flux, 1000+ lignes), HtmlStyleState (100+ champs de propriétés CSS avec un modèle d’héritage par pile), HtmlBlockHandler (répartition des blocs couplée à l’état de style), FlexLayoutEngine (mesure et mise en page flex complètes) et TableParser (pagination colspan/rowspan à travers les sauts de page). Traite toute modification ici comme un travail en mode plan.
Cette page sert de point d’entrée. Les pages de détail sont : pipeline pour la séquence des étapes, css-resolver pour la cascade et la spécificité, layer-contracts-adr010 pour les frontières de couches et streaming-constraints-adr001 pour le modèle sans arbre conservé et ses plafonds.
Texte de droite à gauche et bidirectionnel
Section intitulée « Texte de droite à gauche et bidirectionnel »writeHtml() rend du contenu de droite à gauche (RTL). Définis la propriété CSS direction: rtl sur le corps, un tableau ou n’importe quel élément. Le moteur résout l’ordre visuel avec l’algorithme bidirectionnel Unicode (UAX #9) au travers du moteur bidirectionnel de la couche typographie — voir Typographie pour le détail de BidiEngine. Un contenu mêlant latin, arabe et chiffres s’ordonne correctement, et un nombre placé après de l’arabe conserve ses chiffres de gauche à droite.
L’arabe bénéficie aussi d’une mise en forme contextuelle : le moteur sélectionne la forme initiale, médiane, finale ou isolée de chaque lettre et applique la ligature Lam-Alef. La mise en forme nécessite une police enregistrée dont la table de caractères couvre le bloc Arabic Presentation Forms-B ; une fonte uniquement latine, y compris les polices standard-14, ne peut pas tracer l’arabe. Dans les tableaux, chaque cellule est réordonnée et mise en forme indépendamment et s’aligne sur le bord de début (droite) sous direction: rtl. Le RTL s’applique à l’arabe, à l’hébreu, au persan et à l’ourdou ; l’hébreu est réordonné mais pas mis en forme.
Définis la direction avec la propriété CSS direction — l’attribut HTML dir n’y est pas mappé. L’alignement horizontal des blocs et du texte en ligne hors tableau, ainsi que text-align: justify, ne sont pas encore appliqués. Pour une facture arabe exécutable et la liste complète des limites actuelles, voir Rendre du HTML arabe de droite à gauche.
Surface d’API
Section intitulée « Surface d’API »| Symbole | Emplacement | Rôle |
|---|---|---|
Document::writeHtml(string $html): static | src/Core/Concerns/HasTextOutput.php | Point d’entrée public. Rend le HTML à la position courante du curseur. |
Document::createStandalone(): self | src/Core/Document.php | Construit un document autonome. |
HtmlParser::parse(string $html): HtmlRenderResult | src/Html/HtmlParser.php | Orchestrateur interne. |
HtmlRenderResult | src/Html/HtmlRenderResult.php | Résultat immuable : flux, curseur de fin, polices utilisées. |
DefaultHtmlSecurityPolicy | src/Html/DefaultHtmlSecurityPolicy.php | Politique par défaut pour les balises, attributs, règles CSS et URL. |
HtmlSecurityPolicyInterface | src/Contracts/HtmlSecurityPolicyInterface.php | Contrat de politique pour les politiques personnalisées. |
Exemple de code — Démarrage rapide
Section intitulée « Exemple de code — Démarrage rapide »Tiré de 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');Exemple de code — Production
Section intitulée « Exemple de code — Production »Un rapport tabulaire avec un bloc de style intégré, calqué sur 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);}Cas limites et pièges
Section intitulée « Cas limites et pièges »- Sous-ensemble CSS sélectionné. La prise en charge se fait par module et elle est figée. Vérifie la matrice de prise en charge CSS avant de t’appuyer sur une propriété.
- Les plafonds stricts lèvent une exception. 10 Mo d’entrée,
50,000éléments, 100 niveaux d’imbrication : chacun lèveHtmlParsingException. Voir contraintes de flux. - Pas de remise en page. La sortie est écrite une seule fois dans l’ordre du document ; des styles tardifs ne peuvent pas modifier une sortie antérieure.
:has()reste verrouillé derrière la fonctionnalité expérimentalecss.has.- Sous-système à risque critique. Cinq fichiers en zone dangereuse. Utilise le mode plan pour les modifications sous
src/Html/.
Contraintes du flux à passe unique (ADR-001)
Section intitulée « Contraintes du flux à passe unique (ADR-001) »Le moteur de rendu ne conserve aucun arbre de document et exécute une seule passe, dans l’ordre d’entrée. Les plafonds d’éléments, d’imbrication et d’entrée sont des limites strictes. Le détail complet et le contrat de sûreté côté worker figurent dans contraintes de flux (ADR-001).
Contrats de couches (ADR-010)
Section intitulée « Contrats de couches (ADR-010) »L’analyse CSS, l’état de style, la mise en page et la peinture sont séparés en quatre couches avec des contrats unidirectionnels, ainsi que les ajouts de média paginé et de mesure. Détail complet dans contrats de couches (ADR-010).
Budget mémoire pour les documents volumineux
Section intitulée « Budget mémoire pour les documents volumineux »La mémoire utilisée par l’état de style et le curseur est en O(profondeur d’imbrication), pas en O(nombre d’éléments). Le performance_budget par page est peak_mb: 64. Le plafond de 50,000 éléments reste strict ; répartis les entrées plus grandes sur plusieurs appels writeHtml(). Détail dans contraintes de flux.
Performance
Section intitulée « Performance »Le parcours est en O(nombre de tokens). Le dimensionnement des colonnes de tableau ajoute un balayage borné des lignes par tableau. Le pré-balayage facultatif :has() ajoute une passe bornée sur la liste de tokens. Le benchmark de performance du pipeline de rendu HTML applique un seuil de régression de 5 % (travail fusionné, PR #564). Le performance_budget par page (wall_ms: 1500, peak_mb: 64) est le plafond opérationnel.
Notes de sécurité
Section intitulée « Notes de sécurité »DefaultHtmlSecurityPolicy applique une liste d’autorisation de balises, d’attributs, de propriétés CSS et de schémas d’URL, plus un plafond d’entrée de 10 Mo et un plafond d’imbrication de 100 niveaux, indépendamment de l’analyseur. La liste d’autorisation des propriétés CSS constitue le plafond de sécurité. Le tableau de prise en charge à l’exécution est un plafond de capacité distinct. Implémente HtmlSecurityPolicyInterface pour fournir une politique plus stricte. La récupération de ressources externes est gouvernée séparément par DefaultExternalResourcePolicy.
Dans les valeurs href et les src d’image, la liste d’autorisation d’URL rejette aussi les chemins enracinés sur un antislash (\…) et UNC (\\host\share), en plus de rejeter déjà les chemins relatifs au protocole (//) et de n’autoriser que http(s) ou les chemins relatifs. Les antislashs sont normalisés en barres obliques avant la vérification, de sorte qu’une inclusion de fichier local par chemin absolu Windows ou une récupération sur partage SMB — ni l’une ni l’autre ne portant de schéma URI — ne peut passer par la branche « pas de schéma, donc relatif ».
Extrait de la matrice de prise en charge CSS (lignes Vérifiées uniquement)
Section intitulée « Extrait de la matrice de prise en charge CSS (lignes Vérifiées uniquement) »Cette page ne détaille pas à nouveau la prise en charge propriété par propriété. La matrice de prise en charge CSS est la seule source faisant autorité pour le statut vérifié par module W3C, y compris pour distinguer les modules Vérifiés des modules Revendiqués.
Conformité
Section intitulée « Conformité »Le sous-système implémente un sous-ensemble CSS sélectionné, figé sur des versions de spécification fixes. Les correspondances comportementales avec les spécifications pour la cascade sont documentées avec des identifiants de clause et de chunk dans css-resolver. Le statut de conformité par module est dans la matrice de prise en charge CSS.
Contexte commercial
Section intitulée « Contexte commercial »Capacité Enterprise. Premium élargit la couverture CSS (impression avancée et modules supplémentaires) en conservant le même pipeline à passe unique. L’architecture, les plafonds et les contrats de couches sont les mêmes d’une édition à l’autre. Voir la matrice de prise en charge CSS.