Kontrak lapisan engine HTML (ADR-010)
Sekilas
Bagian berjudul “Sekilas”Subsistem Hypertext Markup Language (HTML) memisahkan penguraian Cascading Style Sheets (CSS), state gaya, tata letak, dan paint ke dalam empat lapisan. Data mengalir satu arah melewati lapisan-lapisan tersebut. Architecture Decision Record 010 (ADR-010) mendefinisikan batas dan aturan ekstensinya.
Pemasangan
Bagian berjudul “Pemasangan”composer require nextpdf/core:^3Gambaran konseptual
Bagian berjudul “Gambaran konseptual”Architecture Decision Record 010 (ADR-010) (“Engine Layer Contracts, Hot Path Ownership, and Extension Rules”, disetujui 2026-04-12) memformalkan pelapisan subsistem HTML. Kontrak rendering inti memiliki empat lapisan: penguraian dan applicator CSS, state gaya, tata letak dan pemformatan, serta paint. ADR-010 juga mendokumentasikan dua lapisan tambahan: paged media dan harness pengukuran. Keduanya membungkus inti empat lapisan tanpa mengubah aliran datanya. Istilah glosarium kanonis untuk inti ini adalah “HTML pipeline”, yaitu pipeline empat lapisan.
Data mengalir dalam satu arah. Teks CSS menjadi nilai bertipe di Lapisan 1. Lapisan 1 menulis nilai-nilai tersebut ke field HtmlStyleState di Lapisan 2. Lapisan 3 membaca field state gaya dan menghitung geometri. Lapisan 4 membaca snapshot ComputedStyle yang imutabel beserta geometri, lalu menghasilkan operator Portable Document Format (PDF). Tidak ada lapisan yang membaca dari lapisan setelahnya.
Pemisahan empat lapisan ini bukan sekadar dokumentasi. ADR-010 mencatat dua refaktor terbatas pada v1.2.0 yang memindahkan kode ke lapisan yang tepat. PageBorderPainter diekstraksi dari HtmlParser, sehingga operator paint tidak lagi berada di orkestrator. Docblock kelas HtmlStyleState kini memuat kontrak lapisan formal dan menyatakan field mana yang boleh ditulis atau dibaca oleh setiap lapisan.
Ada satu batas eksplisit. FormattingContextFactory::startTable() masih membaca lima kunci CSS mentah secara langsung. ADR-010 mencatat hal ini sebagai utang teknis yang diketahui dan ditangguhkan untuk TableApplicator di masa depan, bukan sebagai kontrak yang dimaksudkan. Mendokumentasikan pengecualian ini merupakan bagian dari kontrak.
Empat lapisan inti
Bagian berjudul “Empat lapisan inti”| Lapisan | Berkas (representatif) | Menulis | Membaca | Tidak boleh |
|---|---|---|---|---|
| 1 — Penguraian & applicator CSS | CssValueParser, CssResolver, HtmlCssApplicator, src/Html/Applicator/* | Field CSS HtmlStyleState | Teks CSS mentah | Menghitung geometri; mengeluarkan operator |
| 2 — State gaya | HtmlStyleState, State/ComputedStyle, State/LayoutState | — (wadah nilai pasif) | — | Mengurai CSS; menentukan tata letak; menghasilkan operator |
| 3 — Tata letak & pemformatan | FormattingContextFactory, HtmlBlockHandler, FlexLayoutEngine, TableParser, FloatContext | Geometri kursor | Field HtmlStyleState | Membaca $css[...] mentah; mengeluarkan operator paint |
| 4 — Paint & rendering | BorderRenderer, BackgroundImageRenderer, src/Html/Paint/*, src/Html/Gradient/* | Aliran operator PDF | ComputedStyle (imutabel) + geometri | Menghitung geometri; mengurai CSS; menentukan pemenggalan halaman |
Dua lapisan tambahan
Bagian berjudul “Dua lapisan tambahan”| Lapisan | Berkas (representatif) | Peran |
|---|---|---|
| 5 — Paged media | PageBreakController, PageBorderPainter, PageRule, PageRuleParser, ParserConfigurator | Menyelesaikan aturan @page; mengevaluasi batasan pemenggalan dan orphan/widow; mendelegasikan dekorasi halaman ke paint. |
| 6 — Pengukuran & harness | Skrip pengklasifikasi Web Platform Tests (WPT), tests/Support/* | Mengklasifikasikan hasil pengujian; menghasilkan snapshot regresi; menyediakan helper asersi. Tidak membawa logika rendering. |
Permukaan API
Bagian berjudul “Permukaan API”Kontrak ditegakkan melalui penempatan kelas dan docblock HtmlStyleState. Verifikasi dilakukan terhadap src/Html/.
| Simbol | Lapisan | Peran kontrak |
|---|---|---|
PropertyApplicatorInterface | 1 | Antarmuka strategi; satu-satunya tempat untuk menulis field CSS terkomputasi. |
ParserConfigurator::buildCssApplicator() | 1 (wiring) | Mendaftarkan setiap applicator. Properti CSS baru didaftarkan di sini. |
HtmlStyleState | 2 | Wadah dua grup; docblock kelas menyatakan lapisan pemilik untuk setiap field. |
HtmlStyleState::toComputedStyle() | 2 | Menghasilkan ComputedStyle yang imutabel untuk lapisan paint. |
FormattingContextFactory::dispatchOpenTag() | 3 | Titik perutean tunggal untuk perilaku tata letak baru. |
PageBorderPainter::buildStream() | 4 | Dekorasi halaman; dipanggil dari Lapisan 5, tidak disisipkan inline di HtmlParser. |
Contoh kode — Mulai cepat
Bagian berjudul “Contoh kode — Mulai cepat”Anda tidak pernah berinteraksi langsung dengan lapisan. Alur empat lapisan berjalan di dalam satu panggilan.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->addPage();$doc->writeHtml('<p style="color:#1E3A8A;border:1px solid #999;">Layered render.</p>');$doc->save(__DIR__ . '/output/layers.pdf');Contoh kode — Produksi
Bagian berjudul “Contoh kode — Produksi”Kontrak ini penting saat Anda berkontribusi, bukan saat Anda memanggil pustaka. Untuk menambahkan properti CSS, gunakan titik ekstensi Lapisan 1: buat sebuah applicator, tambahkan field HtmlStyleState bertipe dengan docblock lapisan, lalu daftarkan applicator tersebut di ParserConfigurator. Ilustrasi di bawah ini menunjukkan bentuk kontrak applicator. Gunakan src/Html/Applicator/ sebagai model untuk kelas konkret.
<?php
declare(strict_types=1);
// Layer 1 extension contract (see ADR-010 §C "New CSS property").// A new property group ships as a PropertyApplicatorInterface// implementation registered in ParserConfigurator::buildCssApplicator().// It writes a typed HtmlStyleState field and never computes geometry// or emits PDF operators — those belong to Layers 3 and 4.Kasus khusus & jebakan
Bagian berjudul “Kasus khusus & jebakan”FormattingContextFactory::startTable()membaca CSS mentah. Ini satu-satunya pengecualian kontrak yang terdokumentasi dan ditangguhkan untukTableApplicatordi masa depan. Jangan menyalin pola ini.- Enam lapisan, inti empat lapisan. ADR-010 menomori enam lapisan. Kontrak aliran data adalah inti empat lapisan; paged media dan pengukuran merupakan tambahan.
HtmlStyleStatememiliki dua grup. Ia membawa field terkomputasi CSS dan field pelacakan tata letak. Hanya applicator yang menulis grup CSS. Paint membacaComputedStyle, tidak pernah field pelacakan tata letak.HtmlParsertidak memiliki lapisan. Ia adalah orkestrator. Penguraian CSS, perhitungan geometri, dan emisi paint tidak boleh berada di dalamnya.
Performa
Bagian berjudul “Performa”Kontrak lapisan bersifat struktural, sehingga tidak menambah biaya runtime. HtmlStyleState::toComputedStyle() menghasilkan satu snapshot imutabel untuk setiap elemen yang membutuhkan paint. Snapshot itu memungkinkan kode paint menghindari wadah state yang mutabel. Biaya render diatur oleh model streaming, bukan oleh pelapisan. performance_budget per halaman (wall_ms: 1500, peak_mb: 64) tetap menjadi batas operasional.
Catatan keamanan
Bagian berjudul “Catatan keamanan”Pemisahan lapisan mendukung model keamanan. Lapisan 1 mengurai dan menyaring nilai CSS sesuai kebijakan sebelum kode tata letak atau paint melihatnya, sehingga DefaultHtmlSecurityPolicy::isCssPropertyAllowed() tetap menjadi gerbang tunggal. Paint tidak pernah membaca CSS mentah yang dikendalikan penyerang. Lihat model keamanan modul HTML.
Kesesuaian
Bagian berjudul “Kesesuaian”Halaman ini tidak mengutip standar eksternal apa pun. Batas lapisan berasal dari ADR-010 dan docblock kelas HtmlStyleState, yang mengodekan kontrak di dalam sumber. Kesesuaian perilaku CSS didokumentasikan di css-resolver.
Konteks komersial
Bagian berjudul “Konteks komersial”Kapabilitas Enterprise. Fitur CSS Premium menggunakan empat lapisan yang sama melalui titik ekstensi yang terdokumentasi. Tidak ada pipeline Premium yang terpisah. Lihat matriks dukungan CSS.