Pipeline rendering HTML
Sekilas pandang
Bagian berjudul “Sekilas pandang”Saat Anda memanggil writeHtml(), fungsi ini menjalankan satu lintasan maju terhadap HyperText Markup Language (HTML): melakukan tokenisasi masukan, meresolusi @page dan gaya, menata konten, serta menggambar operator Portable Document Format (PDF). Fungsi ini tidak mempertahankan pohon elemen di antara tahap.
Pemasangan
Bagian berjudul “Pemasangan”composer require nextpdf/core:^3Gambaran konseptual
Bagian berjudul “Gambaran konseptual”Pipeline rendering HTML mengonversi HTML+CSS, yaitu HTML ditambah Cascading Style Sheets (CSS), menjadi operator aliran-konten PDF dalam satu lintasan maju. Pipeline ini tidak membangun pohon dokumen yang dipertahankan. Tahap-tahap di bawah ini mencerminkan HtmlParser::parse() pada main.
Tahap 1 — Sanitasi dan normalisasi. HtmlParser::parse() menolak masukan yang melebihi 10 MB, membuang karakter kontrol, dan menormalisasi akhir baris: baik CRLF maupun CR tunggal menjadi LF, sesuai dengan normalisasi akhir baris HTML pada sumbernya. Setelah itu, fungsi ini mengatur ulang setiap bidang instance, sehingga state dari pemanggilan sebelumnya tidak terbawa ke pemanggilan berikutnya.
Tahap 2 — Ekstraksi blok @page dan gaya. Pengurai terlebih dahulu mengekstraksi blok <style>, lalu menerapkan aturan @page yang ditemukan untuk mengonfigurasi ulang geometri halaman. Pengurai melakukan ini sebelum memproses token apa pun, karena ukuran halaman memengaruhi setiap keputusan tata letak berikutnya.
Tahap 3 — Tokenisasi. HtmlTokenizer::cleanHtml() menormalisasi spasi kosong sambil mempertahankan konten <pre>. tokenize() kemudian menghasilkan list<HtmlToken> yang datar. Ini adalah daftar token, bukan graf node. Pipeline langsung membuang token teks yang hanya berisi spasi kosong. HtmlChildScanner::scan() membangun peta indeks (jumlah anak, jumlah tag, kekosongan) untuk daftar datar tersebut, sehingga selektor struktural tidak memerlukan pohon.
Tahap 4 — Pemindaian awal :has() opsional. Saat Anda mengaktifkan fitur eksperimental css.has, CssResolver::resolveHasSelectors() menjalankan satu pemindaian awal terbatas atas daftar token untuk meresolusi selektor relasional. Langkah terbatas yang terdokumentasi ini adalah pengecualian terhadap aturan lintasan tunggal.
Tahap 5 — Pemrosesan token (gaya, tata letak, penggambaran). HtmlParser::processTokens() menelusuri daftar token satu kali. Untuk setiap elemen, fungsi ini meresolusi kaskade (aplikator Layer 1 menulis HtmlStyleState), menghitung geometri (tata letak Layer 3), dan memancarkan operator PDF (penggambaran Layer 4). Pewarisan gaya menggunakan tumpukan HtmlStyleState push-and-pop. Kursor (x, y, margin, ofset aliran) berpindah antarhandler melalui snapshot HtmlBlockCursor.
Tahap 6 — Pengembalian hasil. parse() mengembalikan HtmlRenderResult yang imutabel beserta aliran konten yang dipancarkan, posisi kursor akhir, dan kunci fon yang digunakan. Pemanggil (writeHtml()) meneruskan kursor kembali ke kerangka koordinat halaman.
Untuk pemisahan empat lapisan di dalam Tahap 5, lihat halaman kontrak lapisan. Untuk properti tanpa pohon yang dipertahankan beserta batasannya, lihat halaman batasan streaming.
Permukaan API
Bagian berjudul “Permukaan API”| Simbol | Lokasi | Tahap |
|---|---|---|
Document::writeHtml(string $html): static | src/Core/Concerns/HasTextOutput.php | Titik masuk publik |
HtmlParser::parse(string $html): HtmlRenderResult | src/Html/HtmlParser.php | Mengorkestrasi semua tahap |
HtmlTokenizer::cleanHtml() / tokenize() | src/Html/HtmlTokenizer.php | Tahap 3 |
HtmlChildScanner::scan() | src/Html/HtmlChildScanner.php | Peta indeks Tahap 3 |
CssResolver::resolveHasSelectors() | src/Html/CssResolver.php | Tahap 4 (bergerbang) |
HtmlRenderResult (stream, endX, endY, usedFontKeys) | src/Html/HtmlRenderResult.php | Tahap 6 |
Contoh kode — Mulai cepat
Bagian berjudul “Contoh kode — Mulai cepat”Bersumber dari 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>One pass.</p>');$doc->save(__DIR__ . '/output/08-html-basic.pdf');Contoh kode — Produksi
Bagian berjudul “Contoh kode — Produksi”Render laporan bergaya dengan blok <style> yang tersemat. Pipeline mengekstraksi dan menerapkan blok gaya sebelum memproses token apa pun.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Exception\HtmlParsingException;
function renderInvoice(string $bodyHtml, string $out): void{ $doc = Document::createStandalone(); $doc->setTitle('Invoice'); $doc->addPage();
$html = '<style>@page { margin: 20mm; } ' . 'h1 { color: #1E3A8A; } ' . 'table { width: 100%; }</style>' . $bodyHtml;
try { $doc->writeHtml($html); } catch (HtmlParsingException $e) { // Sanitize/cap failures surface here. Do not retry. throw $e; }
$doc->save($out);}Kasus tepi & jebakan
Bagian berjudul “Kasus tepi & jebakan”@pagedibaca sebelum token. Aturan@pagesetelah konten tetap berlaku, karena ekstraksi gaya mendahului tokenisasi. Geometri halaman ditetapkan sebelum Tahap 5.- Spasi kosong
<pre>dipertahankan.cleanHtml()melindungi konten<pre>; pipeline meringkas spasi kosong di tempat lain. :has()berada di balik gate. Jika Anda tidak mengaktifkan fitur eksperimentalcss.has, Tahap 4 tidak berjalan dan selektor:has()tidak cocok.- Satu buffer aliran. Pipeline menulis ke satu buffer string. Pipeline tidak pernah memindahkan konten yang sudah ditulis. Tidak ada penataan ulang.
- Batas berlaku di tengah lintasan. Batas elemen dan penyarangan melempar pada Tahap 5, bukan sebelumnya. Dokumen dapat gagal di tengah jalan.
Kinerja
Bagian berjudul “Kinerja”Pipeline menelusuri dalam O(jumlah token). Penentuan ukuran kolom tabel menambahkan satu pemindaian baris per tabel yang terbatas (Tahap 5, TableParser). Saat diaktifkan, pemindaian awal :has() menambahkan satu lintasan daftar-token yang terbatas (Tahap 4). Memori adalah O(kedalaman penyarangan) untuk tumpukan gaya, bukan O(jumlah elemen); lihat batasan streaming. Tolok ukur kinerja pipeline-render HTML melindungi dari regresi dengan gerbang 5% (pekerjaan yang telah digabungkan, PR #564). performance_budget per halaman (wall_ms: 1500, peak_mb: 64) adalah batas atas operasional.
Catatan keamanan
Bagian berjudul “Catatan keamanan”Tahap 1 adalah batas keamanan pertama: batas masukan 10 MB, pembuangan karakter kontrol, dan normalisasi akhir baris semuanya berjalan sebelum tokenisasi. Selama Tahap 5, DefaultHtmlSecurityPolicy membatasi tag, atribut, properti CSS, dan skema URL yang diizinkan. Lihat model keamanan modul HTML.
Kesesuaian
Bagian berjudul “Kesesuaian”Normalisasi akhir baris mengikuti penanganan akhir baris standar HTML: CRLF dan CR tunggal menjadi LF. Kesesuaian CSS per properti terdokumentasi dalam matriks dukungan CSS, dan perilaku kaskade terdokumentasi pada css-resolver. Halaman ini tidak menyatakan ulang dukungan per properti.
Konteks komersial
Bagian berjudul “Konteks komersial”Kemampuan enterprise. Premium memperluas cakupan CSS pada pipeline yang sama. Urutan enam tahap tidak berubah antar-edisi. Lihat matriks dukungan CSS.