HTML: HTML+CSS를 PDF로 렌더링하는 서브시스템
한눈에 보기
섹션 제목: “한눈에 보기”HTML 서브시스템은 HTML+CSS를 단일 정방향 패스로 PDF 콘텐츠 스트림으로 변환합니다. 엔진에서 규모와 위험도가 가장 큰 서브시스템입니다(src/Html/ 아래 324 개 파일).
composer require nextpdf/core:^3개념 개요
섹션 제목: “개념 개요”HTML 서브시스템은 단일 패스 스트리밍 HTML+CSS-to-PDF 렌더러입니다. 공개 API 표면은 단일 메서드인 Document::writeHtml()입니다. 내부적으로 HtmlParser는 문서 트리를 유지하지 않고 단일 정방향 패스로 입력을 토큰화하고, 스타일을 해석하고, 레이아웃을 계산하고, PDF 연산자를 출력합니다.
범위를 분명히 이해해야 합니다. 이 서브시스템은 유지형(retained-document) 렌더러가 아닙니다. 엘리먼트 그래프를 보유하지 않고, 이미 작성된 콘텐츠를 다시 레이아웃하지 않으며, 파싱이 시작된 후에는 입력 변경을 허용하지 않습니다. 고정된 사양 핀(specification pin)에서 선별된 CSS 하위 집합을 구현합니다. 두 가지 아키텍처 결정이 이를 규율합니다. ADR-001은 단일 패스 스트리밍 모델과 그 상한을 고정합니다. ADR-010은 4 계층 계약(CSS 파싱, 스타일 상태, 레이아웃, 페인트)과 페이지 미디어 및 측정 부속 요소를 고정합니다.
HtmlParser는 모듈 매니페스트에서 위험도가 critical로 평가됩니다. 다섯 개 파일에는 문서화된 위험 구역(danger-zone) 주석이 있습니다. HtmlParser 오케스트레이터(스트리밍 토크나이저, 1000 줄 이상), HtmlStyleState(스택 상속 모델을 갖춘 100 개 이상의 CSS 속성 필드), HtmlBlockHandler(스타일 상태에 결합된 블록 디스패치), FlexLayoutEngine(전체 플렉스 측정 및 레이아웃), TableParser(페이지 나눔 전반에 걸친 colspan/rowspan 페이지네이션)입니다. 이 영역의 변경은 plan 모드 작업으로 취급하십시오.
이 페이지가 진입점입니다. 세부 페이지는 다음과 같습니다. 단계 순서는 pipeline, 캐스케이드와 명시도는 css-resolver, 레이어 경계는 layer-contracts-adr010, 트리를 유지하지 않는 모델과 그 상한은 streaming-constraints-adr001에서 확인하십시오.
오른쪽에서 왼쪽으로 쓰기 및 양방향 텍스트
섹션 제목: “오른쪽에서 왼쪽으로 쓰기 및 양방향 텍스트”writeHtml()은 오른쪽에서 왼쪽으로 쓰는(RTL) 콘텐츠를 렌더링합니다. 본문, 테이블, 또는 임의의 엘리먼트에 CSS direction: rtl 속성을 설정하십시오. 엔진은 타이포그래피 계층의 양방향 엔진을 통해 유니코드 양방향 알고리즘(UAX #9)으로 시각적 순서를 해석합니다 — BidiEngine 세부 사항은 Typography를 참조하십시오. 라틴 문자, 아랍어, 숫자가 섞인 콘텐츠는 올바르게 정렬되며, 아랍어 뒤의 숫자는 자릿수를 왼쪽에서 오른쪽으로 유지합니다.
아랍어는 문맥 셰이핑도 거칩니다. 엔진은 각 문자의 어두형, 어중형, 어말형, 또는 고립형을 선택하고 Lam-Alef 합자를 적용합니다. 셰이핑에는 문자 맵이 Arabic Presentation Forms-B 블록을 포괄하는 등록된 글꼴이 필요합니다. standard-14 글꼴을 포함한 라틴 전용 페이스는 아랍어를 그릴 수 없습니다. 테이블에서는 각 셀이 개별적으로 재정렬되고 셰이핑되며, direction: rtl에서는 시작(오른쪽) 가장자리에 정렬됩니다. RTL은 아랍어, 히브리어, 페르시아어, 우르두어에 적용됩니다. 히브리어는 재정렬되지만 셰이핑되지는 않습니다.
방향은 CSS direction 속성으로 설정하십시오 — HTML dir 속성은 이에 매핑되지 않습니다. 테이블 외 블록 및 인라인 텍스트의 수평 정렬과 text-align: justify는 아직 적용되지 않습니다. 실행 가능한 아랍어 인보이스와 현재 제한 사항 전체 목록은 오른쪽에서 왼쪽으로 쓰는 아랍어 HTML 렌더링을 참조하십시오.
API 표면
섹션 제목: “API 표면”| 심볼 | 위치 | 역할 |
|---|---|---|
Document::writeHtml(string $html): static | src/Core/Concerns/HasTextOutput.php | 공개 진입점. 현재 커서 위치에 HTML을 렌더링합니다. |
Document::createStandalone(): self | src/Core/Document.php | 독립 실행형 문서를 생성합니다. |
HtmlParser::parse(string $html): HtmlRenderResult | src/Html/HtmlParser.php | 내부 오케스트레이터. |
HtmlRenderResult | src/Html/HtmlRenderResult.php | 불변 결과: 스트림, 종료 커서, 사용된 글꼴. |
DefaultHtmlSecurityPolicy | src/Html/DefaultHtmlSecurityPolicy.php | 기본 tag/attribute/CSS/URL 정책. |
HtmlSecurityPolicyInterface | src/Contracts/HtmlSecurityPolicyInterface.php | 사용자 지정 정책을 위한 정책 계약. |
코드 샘플 — 빠른 시작
섹션 제목: “코드 샘플 — 빠른 시작”출처: 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>Direct to PDF.</p>');$doc->save(__DIR__ . '/output/08-html-basic.pdf');코드 샘플 — 프로덕션
섹션 제목: “코드 샘플 — 프로덕션”임베디드 스타일 블록을 포함한 표 리포트이며, examples/09-html-table.php를 모델로 삼았습니다.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Exception\HtmlParsingException;
function renderInventory(string $rowsHtml, string $out): void{ $doc = Document::createStandalone(); $doc->setTitle('Inventory'); $doc->addPage();
$html = '<style>table { width: 100%; } ' . 'th { background-color: #1E3A8A; color: #FFFFFF; }</style>' . '<table border="1" cellpadding="5">' . $rowsHtml . '</table>';
try { $doc->writeHtml($html); } catch (HtmlParsingException $e) { // Input cap, element cap (50,000), or nesting cap (100). Do not retry. throw $e; }
$doc->save($out);}엣지 케이스 및 주의 사항
섹션 제목: “엣지 케이스 및 주의 사항”- 선별된 CSS 하위 집합. 지원 범위는 모듈별로 결정되며 핀으로 고정됩니다. 속성에 의존하기 전에 CSS 지원 매트릭스를 확인하십시오.
- 하드 상한은 예외를 발생시킵니다. 입력 10 MB, 엘리먼트
50,000개, 중첩 100 단계 — 각각HtmlParsingException을 발생시킵니다. 스트리밍 제약을 참조하십시오. - 재레이아웃 없음. 출력은 문서 순서대로 한 번 작성되며, 나중에 적용되는 스타일은 앞서 작성된 출력을 변경할 수 없습니다.
:has()는 게이트로 차단되어 있습니다.css.has실험적 기능 뒤에 둡니다.- 위험도 critical 서브시스템. 위험 구역 파일은 다섯 개입니다.
src/Html/아래의 변경에는 plan 모드를 사용하십시오.
단일 패스 스트리밍 제약 (ADR-001)
섹션 제목: “단일 패스 스트리밍 제약 (ADR-001)”렌더러는 문서 트리를 유지하지 않고 단일 정방향 패스를 실행합니다. 엘리먼트, 중첩, 입력 상한은 하드 제한입니다. 전체 세부 사항과 워커 안전 계약은 스트리밍 제약 (ADR-001)에 있습니다.
레이어 계약 (ADR-010)
섹션 제목: “레이어 계약 (ADR-010)”CSS 파싱, 스타일 상태, 레이아웃, 페인트는 단방향 계약을 갖는 네 개의 레이어로 분리되며, 여기에 페이지 미디어와 측정 부속 요소가 추가됩니다. 전체 세부 사항은 레이어 계약 (ADR-010)을 참조하십시오.
대용량 문서를 위한 메모리 예산
섹션 제목: “대용량 문서를 위한 메모리 예산”스타일 상태와 커서 메모리는 O(엘리먼트 수)가 아니라 O(중첩 깊이)입니다. 페이지별 performance_budget은 peak_mb: 64입니다. 엘리먼트 50,000개 상한은 하드 한계입니다. 더 큰 입력은 여러 번의 writeHtml() 호출로 나누십시오. 세부 사항은 스트리밍 제약을 참조하십시오.
순회는 O(토큰 수)입니다. 표 열 크기 조정은 표마다 제한된 행 스캔을 추가합니다. 선택적 :has() 사전 스캔은 제한된 토큰 목록 패스 하나를 추가합니다. HTML 렌더 파이프라인 성능 벤치마크에는 5% 회귀 게이트가 적용됩니다(병합된 작업, PR #564). 페이지별 performance_budget(wall_ms: 1500, peak_mb: 64)이 운영상의 상한입니다.
보안 참고 사항
섹션 제목: “보안 참고 사항”DefaultHtmlSecurityPolicy는 태그, 속성, CSS 속성, URL 스킴의 허용 목록과 함께 10 MB 입력 상한 및 100 단계 중첩 상한을 파서와 독립적으로 적용합니다. CSS 속성 허용 목록은 보안 상한입니다. 런타임 지원 표는 별도의 기능 상한입니다. 더 엄격한 정책을 제공하려면 HtmlSecurityPolicyInterface를 구현하십시오. 외부 리소스 가져오기는 DefaultExternalResourcePolicy에 의해 별도로 규율됩니다.
URL 허용 목록은 href 및 이미지 src 값에서 백슬래시로 시작하는(\…) 경로와 UNC(\\host\share) 경로도 거부합니다. 이는 기존의 프로토콜 상대(//) 거부 및 http(s) 전용 또는 상대 경로 전용 허용 목록과 함께 적용됩니다. 백슬래시는 검사 전에 슬래시로 정규화되므로, URI 스킴을 포함하지 않는 Windows 절대 경로의 로컬 파일 포함이나 SMB 공유 페치 중 어느 것도 “스킴 없음, 따라서 상대 경로” 분기로 빠져나갈 수 없습니다.
CSS 지원 매트릭스 발췌 (Verified 행만)
섹션 제목: “CSS 지원 매트릭스 발췌 (Verified 행만)”이 페이지는 속성별 지원 내용을 다시 기술하지 않습니다. CSS 지원 매트릭스는 어떤 모듈이 Verified인지 Claimed인지를 포함하여, W3C 모듈별 검증 상태에 대한 단일 권위입니다.
적합성
섹션 제목: “적합성”서브시스템은 고정된 사양 핀에서 선별된 CSS 하위 집합을 구현합니다. 캐스케이드 동작의 사양 매핑은 css-resolver에 조항 및 청크 식별자와 함께 문서화되어 있습니다. 모듈별 적합성 상태는 CSS 지원 매트릭스에 있습니다.
상업적 맥락
섹션 제목: “상업적 맥락”Enterprise 기능. Premium은 동일한 단일 패스 파이프라인에서 CSS 커버리지(고급 인쇄 및 추가 모듈)를 확장합니다. 아키텍처, 상한, 레이어 계약은 모든 에디션에서 동일합니다. CSS 지원 매트릭스를 참조하십시오.