Lewati ke konten

Kontrak lapisan engine HTML (ADR-010)

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.

Terminal window
composer require nextpdf/core:^3

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.

LapisanBerkas (representatif)MenulisMembacaTidak boleh
1 — Penguraian & applicator CSSCssValueParser, CssResolver, HtmlCssApplicator, src/Html/Applicator/*Field CSS HtmlStyleStateTeks CSS mentahMenghitung geometri; mengeluarkan operator
2 — State gayaHtmlStyleState, State/ComputedStyle, State/LayoutState— (wadah nilai pasif)Mengurai CSS; menentukan tata letak; menghasilkan operator
3 — Tata letak & pemformatanFormattingContextFactory, HtmlBlockHandler, FlexLayoutEngine, TableParser, FloatContextGeometri kursorField HtmlStyleStateMembaca $css[...] mentah; mengeluarkan operator paint
4 — Paint & renderingBorderRenderer, BackgroundImageRenderer, src/Html/Paint/*, src/Html/Gradient/*Aliran operator PDFComputedStyle (imutabel) + geometriMenghitung geometri; mengurai CSS; menentukan pemenggalan halaman
LapisanBerkas (representatif)Peran
5 — Paged mediaPageBreakController, PageBorderPainter, PageRule, PageRuleParser, ParserConfiguratorMenyelesaikan aturan @page; mengevaluasi batasan pemenggalan dan orphan/widow; mendelegasikan dekorasi halaman ke paint.
6 — Pengukuran & harnessSkrip pengklasifikasi Web Platform Tests (WPT), tests/Support/*Mengklasifikasikan hasil pengujian; menghasilkan snapshot regresi; menyediakan helper asersi. Tidak membawa logika rendering.

Kontrak ditegakkan melalui penempatan kelas dan docblock HtmlStyleState. Verifikasi dilakukan terhadap src/Html/.

SimbolLapisanPeran kontrak
PropertyApplicatorInterface1Antarmuka strategi; satu-satunya tempat untuk menulis field CSS terkomputasi.
ParserConfigurator::buildCssApplicator()1 (wiring)Mendaftarkan setiap applicator. Properti CSS baru didaftarkan di sini.
HtmlStyleState2Wadah dua grup; docblock kelas menyatakan lapisan pemilik untuk setiap field.
HtmlStyleState::toComputedStyle()2Menghasilkan ComputedStyle yang imutabel untuk lapisan paint.
FormattingContextFactory::dispatchOpenTag()3Titik perutean tunggal untuk perilaku tata letak baru.
PageBorderPainter::buildStream()4Dekorasi halaman; dipanggil dari Lapisan 5, tidak disisipkan inline di HtmlParser.

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');

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.
  • FormattingContextFactory::startTable() membaca CSS mentah. Ini satu-satunya pengecualian kontrak yang terdokumentasi dan ditangguhkan untuk TableApplicator di 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.
  • HtmlStyleState memiliki dua grup. Ia membawa field terkomputasi CSS dan field pelacakan tata letak. Hanya applicator yang menulis grup CSS. Paint membaca ComputedStyle, tidak pernah field pelacakan tata letak.
  • HtmlParser tidak memiliki lapisan. Ia adalah orkestrator. Penguraian CSS, perhitungan geometri, dan emisi paint tidak boleh berada di dalamnya.

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.

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.

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.

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.