Repository navigation
Draw @page margin boxes such as @top-center, with counter(page) and counter(pages) #610
Description
Part of #552 (step 28, missing support, medium priority).
The CSS Paged Media margin boxes (@top-left, @top-center, @top-right, @bottom-left, @bottom-center, @bottom-right and the others) are ignored, along with their content. counter(page) and counter(pages) are not available. Print stylesheets written for browsers, Paged.js, WeasyPrint or Prince put running headers and page numbers there. In mPDF they need its own header and footer extensions instead: <htmlpageheader>, odd-header-name on @page, or SetHeader().
Measured on gravitypdf at 60b82630, PHP 8.5.4.
| Document | Browser / paged-media engine | mPDF |
|---|---|---|
@page { margin: 20mm; @top-center { content: "HEADER" } @bottom-right { content: counter(page) } } |
HEADER centred in the top margin, the page number at the bottom right |
neither is drawn; the margin applies |
@page { @bottom-center { content: "Page " counter(page) " of " counter(pages) } } |
Page 1 of 3, and so on |
nothing |
@page :first { @top-center { content: none } } |
no header on page 1 | nothing to remove |
Cause.
CssParsersplits stylesheets with/(.*?)\{(.*?)\}/(src/Css/CssParser.php:219), so a block nested in@pageends the@pagerule at its first}.- Unwrap @supports and @layer and remove other at-rules whole so the rule after them still applies #566 adds
AtRuleProcessor, which removes any at-rule nested in@page, so the next rule is no longer lost. The margin boxes' content is still thrown away. SetPagedMediaCSS()(src/Mpdf.php:16162) reads@pageproperties, and the header and footer names, but nothing that could hold content.
Fix. Map the six top and bottom boxes onto mPDF's own non-HTML headers and footers. They already have left, centre and right cells, and page-number placeholders:
- Parsing. In
AtRuleProcessor, keep the margin boxes of each@pagerule, including:first,:left,:rightand named pages, as a list per page selector. - Content.
contentaccepts strings,counter(page)andcounter(pages), which become{PAGENO}and{nb}, andnone.counter(page, lower-roman)and the other list styles map to mPDF's page-number styles.string()andelement()(CSS GCPM running elements) are out of scope for a first version.
- Style.
font-*,color,text-alignandvertical-alignfrom the box. - Defining the headers. For each page selector, define a header and footer by name with
DefHeaderByName()andDefFooterByName()(src/Mpdf.php:13851,:13862). Attach them asodd-header-nameand the others already are, so:first,:left/:rightand named pages pick them up through the existing code. - Precedence. An explicit
odd-header-name,<sethtmlpageheader>orSetHeader()call wins over a margin box, so documents that use mPDF's extensions do not change. - Out of scope. The corner and side boxes (
@top-left-corner,@left-middleand so on) have no counterpart in mPDF's headers.
Tests. Each row above, :left and :right pages with mirrorMargins, a named page, margin boxes together with <htmlpageheader> (the mPDF header wins), and counter(page, upper-roman).
Activity