Aller au contenu

Le pipeline HTML

Spec: CSS Cascade 5, §6.1 Spec: CSS Display 3, §2 Evidence: Code-backed

NextPDF rend HTML et CSS en PDF au sein de ton processus PHP — sans navigateur, sans sous-processus par défaut. Cette page explique les étapes en couches de la conversion, ce que le moteur CSS couvre réellement et les cas où déléguer à un véritable moteur de rendu de navigateur est le choix honnête.

« HTML vers PDF » ressemble à une opération unique. En réalité, cela recouvre une cascade, un modèle de boîte, une passe de mise en page et une passe de peinture. Chacune est un problème bien spécifié, avec ses propres modes de défaillance. Un moteur qui les fond en une seule procédure est fragile. Une modification de l’analyse des couleurs peut déplacer une boîte, et tu ne le sauras qu’en lançant le rendu puis en inspectant le résultat.

Le modèle en cours de processus présente un réel avantage : aucun navigateur à installer, aucun bac à sable à gérer et aucune frontière de processus à franchir par sérialisation. Mais cela ne porte ses fruits que si la conversion est décomposée assez proprement pour tester chaque préoccupation isolément. C’est l’architecture qui rend « le rendu de HTML en PHP » digne de confiance, et pas seulement possible.

  • La conversion HTML/CSS s’exécute en cours de processus via writeHtml(). Le résultat est un contenu PDF natif, pas une image d’une page.
  • Elle est en une seule passe et en flux continu. Le tokeniseur produit une liste de jetons. L’analyseur la consomme de gauche à droite, et aucun arbre DOM complet n’est conservé (ADR-001). Des plafonds stricts limitent le nombre d’éléments et la profondeur d’imbrication.
  • Le moteur est organisé en couches explicites : analyse CSS et applicateurs, état de style, mise en page et formatage, peinture et média paginé — avec des règles strictes sur ce que chaque couche peut faire (ADR-010).
  • Le moteur CSS couvre la cascade, le modèle de boîte et la mise en page courante (bloc, en ligne, tableaux, flottants, et plus encore) — substantiel, mais un sous-ensemble défini de ce qu’implémente un navigateur moderne.
  • Lorsque tu as besoin d’une fidélité exacte à celle d’un navigateur pour du CSS moderne arbitraire, NextPDF peut déléguer à un moteur de rendu de navigateur sans interface graphique via une extension optionnelle — une jonction délibérée, isolée du réseau, pas le chemin par défaut.

La conversion est une séquence d’étapes, chacune consommant la sortie typée de l’étape précédente.

  1. Tokenize HTML becomes an ordered token list — no retained DOM tree.
  2. Resolve CSS Parse styles ; the cascade and applicators compute typed values.
  3. Style state A push/pop style stack carries computed values per nesting level.
  4. Layout Block, inline, table, and float geometry computed ; no paint here.
  5. Paint Borders, backgrounds, text, and decorations emit PDF operators.
  6. Paged media Page-break and @page rules applied as the cursor crosses page bounds.
Le pipeline HTML en cours de processus : une seule passe de gauche à droite sur un flux de jetons, avec la résolution CSS, l'état de style, la mise en page et la peinture comme couches distinctes, et les sauts de média paginé appliqués au fur et à mesure que le curseur avance.

Deux règles architecturales en font plus qu’un simple flux.

Les couches ont des contrats. Le texte CSS n’est lu qu’à l’intérieur des classes d’applicateurs. Le code de mise en page calcule la géométrie mais n’émet aucun opérateur de peinture. Le code de peinture lit un instantané immuable de style calculé, jamais l’état mutable de suivi de mise en page. Le code de média paginé déclenche les sauts mais délègue la décoration de page à la couche de peinture. Ces frontières sont appliquées (ADR-010). C’est pourquoi une nouvelle propriété CSS devient un nouvel applicateur, plutôt qu’une modification qui se répercute à la fois dans l’analyseur, le dispatch de mise en page et le peintre.

Il n’y a pas de DOM. Le pipeline est en une seule passe et en flux continu par choix architectural (ADR-001) : au plus un état de style par niveau d’imbrication, plus le curseur actif, pas un objet par élément. Quelques opérations ont réellement besoin d’anticipation — le dimensionnement des colonnes de tableau, :has(), :last-child. Elles sont gérées par des structures d’index de préanalyse bornées sur la liste plate de jetons, et non par la conservation d’un arbre. Le nombre d’éléments et la profondeur d’imbrication sont strictement plafonnés, de sorte qu’une entrée pathologique échoue rapidement au lieu d’épuiser la mémoire.

Le moteur CSS résout une vraie sémantique CSS, pas une imitation. Les déclarations concurrentes sont réduites à une seule valeur par propriété selon l’origine, l’importance, la couche, la spécificité et l’ordre — la cascade réelle. La mise en page suit le modèle de boîte. Le type d’une boîte et le contexte de formatage qu’elle établit déterminent la façon dont elle et les boîtes sœurs dans le flux sont placées. Le code source du moteur est organisé exactement autour de ces préoccupations (cascade, box/display, flex, float, tableaux, fragmentation). C’est pourquoi tu peux raisonner sur son comportement au regard des spécifications, plutôt que de le découvrir empiriquement.

Cette page est Evidence: Code-backed . Les étapes et les règles correspondent au dépôt principal :

  • Le point d’entrée en cours de processus est writeHtml(string $html): static dans src/Core/Concerns/HasTextOutput.php.
  • La conception en une seule passe, sans DOM conservé, avec des plafonds d’éléments et d’imbrication relève d’ADR-001 et du code tokenizer/parser/style-stack dans src/Html/.
  • Le contrat du moteur en couches — parsing/applicators CSS, état de style, mise en page, peinture, média paginé — relève d’ADR-010, ce que reflète l’organisation de src/Html/ (par exemple Cascade/, Css/, Flex/, Float/, Fragmentation/, et les classes d’applicateurs).
  • La jonction de délégation au navigateur est writeHtmlChrome() dans le même fichier, documentée comme nécessitant l’extension optionnelle de moteur de rendu plus un binaire Chrome/Chromium.

Les normes ancrent honnêtement l’affirmation de couverture. La cascade réduit les déclarations concurrentes à une seule valeur par propriété — origine, importance, couche, spécificité, ordre — selon Spec: CSS Cascade 5, §6.1 , et le placement dans le flux suit les règles de boîte et de contexte de formatage selon Spec: CSS Display 3, §2 . La frontière est tout aussi importante : une requête de fonctionnalité existe précisément parce que tous les processeurs ne prennent pas en charge toutes les fonctionnalités selon Spec: CSS Conditional 5, §2 . Le moteur CSS de NextPDF est un sous-ensemble défini et aligné sur les spécifications, et l’énoncer clairement fait partie du contrat.

Le rendu en cours de processus tient en un seul appel. La sortie est du texte PDF sélectionnable, pas une page rastérisée :

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Basic');
$doc->addPage();
$html = <<<'HTML'
<h1 style="color: #1E3A8A;">HTML Rendering in NextPDF</h1>
<p>NextPDF renders <strong>HTML and CSS</strong> directly into PDF pages,
<em>in-process</em>.</p>
<ul>
<li>Headings, paragraphs, bold and italic</li>
<li>Lists, tables, inline styles</li>
</ul>
HTML;
$doc->writeHtml($html);
$doc->save(__DIR__ . '/html-basic.pdf');

Si le même document nécessitait du CSS moderne arbitraire avec une fidélité exacte à celle d’un navigateur, l’appel serait plutôt writeHtmlChrome($html) — même document, chemin de rendu différent, et une dépendance délibérée au moteur de rendu de navigateur optionnel.

L’idée fausse récurrente est qu’un moteur HTML vers PDF est « en quelque sorte un navigateur ». Il ne l’est pas, et il ne prétend pas l’être. Un navigateur est une implémentation vaste et continuellement mise à jour de l’intégralité de la plateforme web. Le moteur en cours de processus de NextPDF est un sous-ensemble aligné sur les spécifications, conçu pour la mise en page de documents. Le modèle mental honnête est « un moteur CSS compétent pour documents imprimés », pas « Chrome en PHP ». Lorsque tu as véritablement besoin de la plateforme complète, c’est à cela que sert writeHtmlChrome(). C’est un chemin distinct, à activation explicite, avec sa propre empreinte opérationnelle, pas un repli silencieux.

Une seconde idée fausse : supposer que le chemin du navigateur consiste simplement à « effectuer le rendu de la page via le réseau ». C’est l’inverse par construction. La jonction de délégation effectue le rendu avec l’accès réseau aux sous-ressources bloqué inconditionnellement — aucune image, police, feuille de style ou frame distante — de sorte qu’elle ne peut pas devenir un vecteur de requêtes sortantes. La fidélité au pixel, oui ; une sortie réseau ouverte, non.

Cette page explique la forme du pipeline et le choix entre rendu interne au processus et navigateur. Ce n’est pas une matrice de prise en charge CSS. Les propriétés, modules et sélecteurs exacts que le moteur en cours de processus couvre sont définis par le code et ses tests de conformité, pas par cette vue d’ensemble. Cette couverture évolue. Le chemin de délégation au navigateur nécessite une extension optionnelle et un binaire Chrome/Chromium. Sa configuration, ses caractéristiques opérationnelles et l’organisation interne de cette extension sont hors du périmètre de cette page et documentées avec ce paquet. « En cours de processus » décrit le chemin par défaut writeHtml(). Ce n’est pas une affirmation selon laquelle tout chemin de rendu évite un sous-processus. Les affirmations architecturales sont exactes à la date de relecture de cette page. Les sources faisant autorité sont src/Html/, ADR-001 et ADR-010 dans le dépôt principal.

Le moteur CSS en cours de processus est une capacité Core. La jonction de délégation au navigateur est une extension optionnelle, exposée ici uniquement au niveau de la capacité :

HTML rendering paths — edition availability
Edition Availability
Core Core fournit le moteur HTML/CSS en cours de processus (writeHtml).
Pro Le chemin de délégation au navigateur est une extension complémentaire optionnelle, indépendante du niveau d’édition.
Enterprise Le chemin de délégation au navigateur est une extension complémentaire optionnelle, indépendante du niveau d’édition.
  • Rendu en cours de processus — convertir HTML/CSS en PDF au sein du processus PHP, sans navigateur ni sous-processus par défaut (writeHtml()).
  • En une seule passe / en flux continu — consommer un flux de jetons de gauche à droite sans conserver d’arbre DOM complet (ADR-001).
  • Cascade — le processus CSS qui résout les déclarations concurrentes en une seule valeur par propriété selon l’origine, l’importance, la couche, la spécificité et l’ordre.
  • Contexte de formatage — l’environnement de mise en page qu’établit une boîte et qui régit la façon dont son contenu dans le flux est placé.
  • Contrat de couche du moteur — l’ensemble de règles appliquées (ADR-010) qui définit ce que chacune des couches d’analyse, de style, de mise en page, de peinture et de média paginé peut faire.
  • Jonction de délégation au navigateur — le chemin optionnel writeHtmlChrome() qui effectue le rendu via un navigateur sans interface graphique avec l’accès réseau aux sous-ressources bloqué.