Kontrakty warstwowe silnika HTML (ADR-010)
W skrócie
Dział zatytułowany „W skrócie”Podsystem Hypertext Markup Language (HTML) dzieli analizę składniową arkuszy Cascading Style Sheets (CSS), stan stylów, układ i malowanie na cztery warstwy. Dane przepływają przez te warstwy tylko w jednym kierunku. Architecture Decision Record 010 (ADR-010) wyznacza granice oraz reguły rozszerzania.
Instalacja
Dział zatytułowany „Instalacja”composer require nextpdf/core:^3Przegląd koncepcyjny
Dział zatytułowany „Przegląd koncepcyjny”Architecture Decision Record 010 (ADR-010) („Engine Layer Contracts, Hot Path Ownership, and Extension Rules”, przyjęty 2026-04-12) formalizuje podział podsystemu HTML na warstwy. Podstawowy kontrakt renderowania obejmuje cztery warstwy: analizę składniową CSS i aplikatory, stan stylów, układ i formatowanie oraz malowanie. ADR-010 dokumentuje również dwie dodatkowe warstwy: nośnik stronicowany i zestaw narzędzi pomiarowych. Otaczają one czterowarstwowy rdzeń, nie zmieniając przepływu danych w jego obrębie. Kanoniczny termin słownikowy dla tego rdzenia to „potok HTML”, czyli czterowarstwowy potok.
Dane przepływają jednokierunkowo. Tekst CSS jest przekształcany w wartości typowane w warstwie 1. Warstwa 1 zapisuje te wartości do pól HtmlStyleState w warstwie 2. Warstwa 3 odczytuje pola stanu stylów i oblicza geometrię. Warstwa 4 odczytuje niezmienną migawkę ComputedStyle wraz z geometrią i emituje operatory Portable Document Format (PDF). Żadna warstwa nie odczytuje danych z warstwy późniejszej.
Podział na cztery warstwy ma znaczenie nie tylko dokumentacyjne. ADR-010 odnotowuje dwie ograniczone refaktoryzacje zastosowane w wersji v1.2.0, które przeniosły kod do właściwej warstwy. PageBorderPainter został wyodrębniony z HtmlParser, więc operatory malowania nie znajdują się już w orkiestratorze. Blok dokumentacyjny klasy HtmlStyleState zawiera teraz formalny kontrakt warstw i określa, które pola każda warstwa może zapisywać lub odczytywać.
Jedno naruszenie granicy jest jawnie opisane. FormattingContextFactory::startTable() nadal odczytuje bezpośrednio pięć surowych kluczy CSS. ADR-010 odnotowuje to jako znany, odroczony dług techniczny dla przyszłego TableApplicator, a nie jako zamierzony kontrakt. Udokumentowanie tego wyjątku jest częścią kontraktu.
Cztery podstawowe warstwy
Dział zatytułowany „Cztery podstawowe warstwy”| Warstwa | Pliki (reprezentatywne) | Zapisuje | Odczytuje | Nie może |
|---|---|---|---|---|
| 1 — analiza składniowa CSS i aplikatory | CssValueParser, CssResolver, HtmlCssApplicator, src/Html/Applicator/* | Pola CSS w HtmlStyleState | Surowy tekst CSS | Obliczać geometrii; emitować operatorów |
| 2 — stan stylów | HtmlStyleState, State/ComputedStyle, State/LayoutState | — (pasywny zbiór wartości) | — | Analizować składniowo CSS; decydować o układzie; emitować operatorów |
| 3 — układ i formatowanie | FormattingContextFactory, HtmlBlockHandler, FlexLayoutEngine, TableParser, FloatContext | Geometria kursora | Pola HtmlStyleState | Odczytywać surowych $css[...]; emitować operatorów malowania |
| 4 — malowanie i renderowanie | BorderRenderer, BackgroundImageRenderer, src/Html/Paint/*, src/Html/Gradient/* | Strumień operatorów PDF | ComputedStyle (niezmienny) + geometria | Obliczać geometrii; analizować składniowo CSS; decydować o podziałach stron |
Dwie warstwy dodatkowe
Dział zatytułowany „Dwie warstwy dodatkowe”| Warstwa | Pliki (reprezentatywne) | Rola |
|---|---|---|
| 5 — nośnik stronicowany | PageBreakController, PageBorderPainter, PageRule, PageRuleParser, ParserConfigurator | Rozwiązuje reguły @page; ocenia ograniczenia podziału oraz orphan/widow; przekazuje dekorację strony do warstwy malowania. |
| 6 — pomiary i zestaw narzędzi | Skrypty klasyfikatora Web Platform Tests (WPT), tests/Support/* | Klasyfikuje wyniki testów; tworzy migawki regresji; udostępnia funkcje pomocnicze do asercji. Nie zawiera logiki renderowania. |
Powierzchnia API
Dział zatytułowany „Powierzchnia API”Kontrakt jest wymuszany przez rozmieszczenie klas oraz blok dokumentacyjny HtmlStyleState. Można go zweryfikować względem src/Html/.
| Symbol | Warstwa | Rola w kontrakcie |
|---|---|---|
PropertyApplicatorInterface | 1 | Interfejs strategii; jedyne miejsce zapisujące pola obliczone z CSS. |
ParserConfigurator::buildCssApplicator() | 1 (montaż) | Rejestruje każdy aplikator. Nową właściwość CSS rejestruje się tutaj. |
HtmlStyleState | 2 | Zbiór z dwiema grupami pól; blok dokumentacyjny klasy wskazuje warstwę będącą właścicielem każdego pola. |
HtmlStyleState::toComputedStyle() | 2 | Tworzy niezmienny ComputedStyle dla warstwy malowania. |
FormattingContextFactory::dispatchOpenTag() | 3 | Pojedynczy punkt routingu dla nowych zachowań układu. |
PageBorderPainter::buildStream() | 4 | Dekoracja strony; wywoływana z warstwy 5, nie wbudowana w HtmlParser. |
Przykład kodu — szybki start
Dział zatytułowany „Przykład kodu — szybki start”Nie sięga się bezpośrednio do warstw. Czterowarstwowy przepływ odbywa się w ramach jednego wywołania.
<?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');Przykład kodu — środowisko produkcyjne
Dział zatytułowany „Przykład kodu — środowisko produkcyjne”Kontrakt ma znaczenie podczas współtworzenia kodu, nie przy samym wywoływaniu biblioteki. Aby dodać właściwość CSS, użyj punktu rozszerzenia warstwy 1: utwórz aplikator, dodaj typowane pole HtmlStyleState z blokiem dokumentacyjnym warstwy i zarejestruj aplikator w ParserConfigurator. Poniższa ilustracja pokazuje kształt kontraktu aplikatora. Dla konkretnej klasy użyj jako wzorca src/Html/Applicator/.
<?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.Przypadki brzegowe i pułapki
Dział zatytułowany „Przypadki brzegowe i pułapki”FormattingContextFactory::startTable()odczytuje surowy CSS. To jedyny udokumentowany wyjątek od kontraktu, odroczony do przyszłegoTableApplicator. Nie powielaj tego wzorca.- Sześć warstw, czterowarstwowy rdzeń. ADR-010 numeruje sześć warstw. Kontrakt przepływu danych dotyczy czterowarstwowego rdzenia; nośnik stronicowany i pomiary są dodatkami.
HtmlStyleStatema dwie grupy pól. Zawiera pola obliczone z CSS oraz pola śledzenia układu. Tylko aplikatory zapisują grupę CSS. Warstwa malowania odczytujeComputedStyle, nigdy pól śledzenia układu.HtmlParsernie należy do żadnej warstwy. Jest orkiestratorem. Analiza składniowa CSS, obliczenia geometrii i emisja operatorów malowania nie mogą się w nim znajdować.
Wydajność
Dział zatytułowany „Wydajność”Kontrakt warstw jest strukturalny, więc nie zwiększa kosztu wykonania. HtmlStyleState::toComputedStyle() tworzy jedną niezmienną migawkę dla każdego elementu wymagającego malowania. Ta migawka pozwala kodowi malowania uniknąć modyfikowalnego zbioru stanu. Koszt renderowania jest regulowany przez model strumieniowy, a nie przez podział na warstwy. Budżet performance_budget dla pojedynczej strony (wall_ms: 1500, peak_mb: 64) pozostaje pułapem operacyjnym.
Uwagi dotyczące bezpieczeństwa
Dział zatytułowany „Uwagi dotyczące bezpieczeństwa”Rozdzielenie warstw wspiera model bezpieczeństwa. Warstwa 1 analizuje składniowo i filtruje wartości CSS zgodnie z polityką, zanim trafią do kodu układu lub malowania, więc DefaultHtmlSecurityPolicy::isCssPropertyAllowed() pozostaje jedyną bramką. Warstwa malowania nigdy nie odczytuje surowego CSS kontrolowanego przez atakującego. Zobacz model bezpieczeństwa modułu HTML.
Zgodność
Dział zatytułowany „Zgodność”Ta strona nie cytuje żadnego zewnętrznego standardu. Granice warstw pochodzą z ADR-010 oraz bloku dokumentacyjnego klasy HtmlStyleState, który utrwala kontrakt w kodzie źródłowym. Zgodność CSS na poziomie zachowania jest udokumentowana na stronie css-resolver.
Kontekst komercyjny
Dział zatytułowany „Kontekst komercyjny”Funkcja dla przedsiębiorstw. Funkcje CSS w wersji Premium korzystają z tych samych czterech warstw przez udokumentowane punkty rozszerzeń. Nie istnieje osobny potok Premium. Zobacz macierz obsługi CSS.