From b491fdf715df8a60d3f79e4f07083867bf4369c1 Mon Sep 17 00:00:00 2001 From: Jake Jackson Date: Wed, 30 Sep 2026 17:59:14 +1000 Subject: [PATCH] Honour !important in stylesheets and inline styles in cssMode standard (mpdf/mpdf#1010) Under the standard cascade, declarations marked !important apply after the inline style: those of the document's stylesheets by specificity and then position, then those of the inline style, then those of the default stylesheet. Each declaration block is split into normal and important declarations, normalised on their own, so a shorthand marked important expands into important longhands. @page, body and SVG class rules take an important declaration over a later one of the same selector. Legacy mode still reads the flag as nothing. In both modes the flag is taken out of the value whatever its spacing and case, so "margin: 5mm ! important" no longer sets margins to "!" and "important". Co-Authored-By: Claude Opus 5.5 --- CHANGELOG-GRAVITYPDF.md | 7 + src/Css/CssMerger.php | 40 +- src/Css/CssParser.php | 94 ++-- src/Css/InlineStyleParser.php | 59 ++- src/Css/RuleSet.php | 26 +- src/CssManager.php | 47 +- src/Mpdf.php | 11 +- tests/Mpdf/Css/CssParserTest.php | 34 ++ tests/Mpdf/Css/InlineStyleParserTest.php | 74 ++++ tests/Mpdf/Css/RuleSetTest.php | 32 +- tests/Mpdf/CssManagerTest.php | 33 ++ tests/Mpdf/ImportantContextTest.php | 150 +++++++ tests/Mpdf/ImportantDeclarationTest.php | 405 ++++++++++++++++++ .../FrameworkImportantLegacySnapshotTest.php | 21 + .../Snapshots/FrameworkImportantSnapshot.php | 122 ++++++ ...FrameworkImportantStandardSnapshotTest.php | 21 + .../ImportantDeclarationsSnapshotTest.php | 128 ++++++ tests/data/css/important-default.css | 13 + .../snapshots/framework-important-legacy.pdf | Bin 0 -> 42666 bytes .../framework-important-standard.pdf | Bin 0 -> 40704 bytes .../data/snapshots/important-declarations.pdf | Bin 0 -> 43625 bytes 21 files changed, 1247 insertions(+), 70 deletions(-) create mode 100644 tests/Mpdf/ImportantContextTest.php create mode 100644 tests/Mpdf/ImportantDeclarationTest.php create mode 100644 tests/Snapshots/FrameworkImportantLegacySnapshotTest.php create mode 100644 tests/Snapshots/FrameworkImportantSnapshot.php create mode 100644 tests/Snapshots/FrameworkImportantStandardSnapshotTest.php create mode 100644 tests/Snapshots/ImportantDeclarationsSnapshotTest.php create mode 100644 tests/data/css/important-default.css create mode 100644 tests/data/snapshots/framework-important-legacy.pdf create mode 100644 tests/data/snapshots/framework-important-standard.pdf create mode 100644 tests/data/snapshots/important-declarations.pdf diff --git a/CHANGELOG-GRAVITYPDF.md b/CHANGELOG-GRAVITYPDF.md index d2c0a85c1..ba0c89c13 100644 --- a/CHANGELOG-GRAVITYPDF.md +++ b/CHANGELOG-GRAVITYPDF.md @@ -42,6 +42,10 @@ Read this section before upgrading from upstream mPDF. Each entry says what chan * Class and id names still match whatever their case. * An author's `a { }` rule now reaches the links of the table of contents and the index too. Style `a.mpdf_toc_a` and `a.mpdf_index_link` to keep them plain. * In legacy mode, a rule whose selector mPDF v7 could not read is dropped: child and sibling combinators, structural pseudo-classes outside tables, attribute selectors other than `[lang]`, `:lang()` through an ancestor, descendant rules through inline ancestors, and `:not()`, `:is()` and `:where()`. The `font`, `border` and `background` shorthands leave the longhands they do not name, as mPDF v7 did. Fixes to how values and selectors are read apply in both modes. [#633] +* **`!important` is honoured**, as in a browser, in standard mode. mPDF read a declaration marked `!important` as any other, so `p { color: green !important } #i { color: red }` drew `

` red, and so did `style="color: red"` on a `

`. Now an important declaration beats every declaration that is not, the inline style included. Set `'cssMode' => \Mpdf\CssMode::LEGACY` to read the flag as nothing, as mPDF v7 did. [mpdf/mpdf#1010] [mpdf/mpdf#1707] [#532] [#638] + * Important declarations apply after the inline style: those of the stylesheets by specificity and then order, then those of `style=""`, then those of the default stylesheet (`defaultCssFile`), as a browser's own important declarations beat a page's. + * A shorthand marked `!important` makes every longhand it sets important, so `border: 1mm solid green !important` beats a `border-top-color` of a more specific rule or of a later declaration in the same block. + * `@page` rules, `body` rules and the class rules SVG text looks up take an important declaration over a later one of the same selector that is not. An important declaration of a `body` rule beats ``. New features ------------ @@ -155,6 +159,7 @@ Bugfixes * Descendant rules naming a table, row or cell, such as `td img` or `td span`, matched nothing inside the cell. [#223] [#507] * A descendant rule with a part mPDF cannot parse was cut short at that part and applied to the element before it. Such rules are now dropped. [#519] * An inline `style` with `!important` drew no border for a `border` shorthand, dropped the bottom padding of a two-value `padding`, drew text at 0pt for a `font-size`, and ignored an image's `height` with a warning. The flag is now removed, as it is from a stylesheet. [mpdf/mpdf#1010] [mpdf/mpdf#1707] [#523] [#561] +* A declaration whose flag had a space after the bang, such as `margin: 5mm ! important`, kept the flag in its value: that margin set the right and left margins to `!` and the bottom one to `important`, a `font-size` was lost, and a `border` drew nothing. The flag is now found whatever its spacing and case, in stylesheets and inline styles, in either `cssMode`. [#532] [#638] * Text styled with the `font` shorthand or `` came out as empty boxes when the family was not installed or had a space in its name, such as `font: 12pt Roboto` or `font: 16px "DejaVu Sans Mono"`. It was drawn in the first registered font, which is the emoji font in a full install. The family is now read as `font-family` reads it: a name is kept whole, the list is tried in order, and when mPDF knows none of it the text keeps the family it inherits. `font-family` itself also reads an unquoted name with spaces whole. [#552] [#560] * A descendant rule ending in `:lang()` or `[lang]`, such as `div :lang(fr)`, `div p:lang(fr)` or `table [lang=fr]`, never applied. It now applies in block content and in tables, and a regional language such as `fr-CA` falls back to the rule for `fr`, as the simple lang rules do. [#525] [#559] * A rule such as `td:nth-child(2):not(.x)` or `td:nth-child(2 of .x)` was applied to the second cell of every row, as if it were `td:nth-child(2)`. A rule with anything after an nth-child argument, or with an argument that is not a formula, is now dropped. [mpdf/mpdf#83] [#522] [#564] @@ -792,6 +797,7 @@ These changes do not change output. [#526]: https://github.com/GravityPDF/mpdf/issues/526 [#527]: https://github.com/GravityPDF/mpdf/issues/527 [#528]: https://github.com/GravityPDF/mpdf/issues/528 +[#532]: https://github.com/GravityPDF/mpdf/issues/532 [#533]: https://github.com/GravityPDF/mpdf/issues/533 [#535]: https://github.com/GravityPDF/mpdf/issues/535 [#536]: https://github.com/GravityPDF/mpdf/issues/536 @@ -844,3 +850,4 @@ These changes do not change output. [#633]: https://github.com/GravityPDF/mpdf/pull/633 [#635]: https://github.com/GravityPDF/mpdf/pull/635 [#634]: https://github.com/GravityPDF/mpdf/pull/634 +[#638]: https://github.com/GravityPDF/mpdf/pull/638 diff --git a/src/Css/CssMerger.php b/src/Css/CssMerger.php index 04b49d37d..cb4a45e91 100644 --- a/src/Css/CssMerger.php +++ b/src/Css/CssMerger.php @@ -160,8 +160,10 @@ public function merge($inherit, $tag, $attr) /** * Merges an element's CSS as standard mode orders it, in layers, each over the one before: the inherited * values, the built-in defaults and the default stylesheet's rules, the presentational attributes as author rules - * of zero specificity, the author rules, and the inline style. The rules of each stylesheet apply by specificity, - * then in the order they were written. + * of zero specificity, the author rules, and the inline style; then the !important declarations of the author + * rules, of the inline style, and of the default stylesheet's rules. The rules of each stylesheet apply by + * specificity, then in the order they were written. Each rule that reaches a table cell draws its borders over + * those of its neighbours. * * @param string $inherit Inheritance context (BLOCK, INLINE, TABLE, TOPTABLE) * @param string $tag HTML tag name @@ -189,45 +191,45 @@ private function mergeInCascadeOrder($inherit, $tag, array $attr) $id = isset($attr['ID']) ? $attr['ID'] : ''; $classes = $this->classesOf($attr); + $dominance = $tag === 'TD' || $tag === 'TH' ? 9 : false; $this->mergeInheritedBlockProperties($inherit, $tag); $this->mergeDefaultCss($tag); - $this->mergeMatchingRules($this->cssManager->getDefaultRules(), $tag, $id, $classes, $path); + list($defaultRules, $importantDefaultRules) = $this->cssManager->getDefaultRules()->matchingDeclarations($tag, $id, $classes, $path); + $this->mergeEach($defaultRules, $dominance); $this->mergeInlineAttributes($tag, $attr); $this->mergeTableSpecificCss($tag, $attr); if ($tag === 'BODY') { // Merged outside the document's elements, and written to by Mpdf::SetDefaultBodyCSS() and the like - $body = isset($this->cssManager->CSS['BODY']) ? $this->cssManager->CSS['BODY'] : []; - $this->setMergedCss($body, false); + $important = $this->cssManager->getImportantCss(); + $importantDefault = $this->cssManager->getDefaultImportantCss(); + $rules = [isset($this->cssManager->CSS['BODY']) ? $this->cssManager->CSS['BODY'] : []]; + $importantRules = isset($important['BODY']) ? [$important['BODY']] : []; + $importantDefaultRules = isset($importantDefault['BODY']) ? [$importantDefault['BODY']] : []; } else { - $this->mergeMatchingRules($this->cssManager->getRules(), $tag, $id, $classes, $path); + list($rules, $importantRules) = $this->cssManager->getRules()->matchingDeclarations($tag, $id, $classes, $path); } + $this->mergeEach($rules, $dominance); - $this->mergeInlineStyle($tag, $attr); + list($inline, $importantInline) = isset($attr['STYLE']) ? $this->inlineStyleParser->parseByImportance($attr['STYLE']) : [[], []]; + $this->mergeEach(array_merge([$inline], $importantRules, [$importantInline], $importantDefaultRules), $dominance); return $this->cssProperties; } /** - * Merges the declarations of the rules in a rule set that an element matches, in the order they apply: by - * specificity, then by their position in the stylesheets. Each rule that reaches a table cell draws its borders - * over those of its neighbours + * Merges sets of properties, each over those before it * - * @param RuleSet $rules - * @param string $tag HTML tag name, uppercased - * @param string $id Uppercased, or empty for none - * @param string[] $classes Uppercased - * @param callable $path Gives the open elements from the document down to the element, or null for none + * @param array[] $sets + * @param int|false $dominance The border dominance each set's borders take in a table cell, or false outside one * @return void */ - private function mergeMatchingRules(RuleSet $rules, $tag, $id, array $classes, callable $path) + private function mergeEach(array $sets, $dominance) { - $dominance = $tag === 'TD' || $tag === 'TH' ? 9 : false; - - foreach ($rules->matchingDeclarations($tag, $id, $classes, $path) as $properties) { + foreach ($sets as $properties) { $this->setMergedCss($properties, false, $dominance); } } diff --git a/src/Css/CssParser.php b/src/Css/CssParser.php index d8d20f2a9..a4e6a323a 100644 --- a/src/Css/CssParser.php +++ b/src/Css/CssParser.php @@ -88,6 +88,12 @@ class CssParser */ private $css = []; + /** + * @var array[] The properties the !important declarations of the rules in $css set, under the same keys. Only + * standard mode keeps them apart + */ + private $importantCss = []; + /** * CSS for cascaded selectors. * @@ -127,8 +133,8 @@ class CssParser private $nthChildFormulas = ['TR' => [], 'TD' => [], 'TH' => []]; /** - * @var array[] The rules of the last CSS parsed for the matcher, each compiled: [compiled selector, declarations], - * in the order they were written + * @var array[] The rules of the last CSS parsed for the matcher, each compiled: [compiled selector, declarations, + * !important declarations], in the order they were written */ private $compiledRules = []; @@ -160,6 +166,7 @@ public function __construct( public function parse($html) { $this->css = []; + $this->importantCss = []; $this->cascadeCSS = []; $this->compiledRules = []; @@ -215,6 +222,17 @@ public function getCss() return $this->css; } + /** + * The properties the !important declarations of the last CSS parsed set, under the keys getCss() uses. Legacy mode + * reads those declarations as any other, into getCss(), and leaves this empty + * + * @return array[] + */ + public function getImportantCss() + { + return $this->importantCss; + } + /** * @return array */ @@ -226,7 +244,7 @@ public function getCascadeCss() /** * The rules of the last CSS parsed for the matcher, in standard mode. Legacy mode compiles none * - * @return array[] Each [compiled selector, declarations], in the order they were written + * @return array[] Each [compiled selector, declarations, !important declarations], in the order they were written */ public function getCompiledRules() { @@ -299,14 +317,14 @@ private function processCssString($css) */ private function processRule($selectors, $declarations) { - $classProperties = $this->parseCssProperties($declarations); + list($classProperties, $important) = $this->parseCssPropertiesByImportance($declarations); if (strpbrk($selectors, "\t\n\r\f\v") !== false) { $selectors = preg_replace(self::WHITESPACE, ' ', $selectors); } foreach ($this->selectorCompiler->splitList($selectors) as $selector) { - $this->processCssSelector($selector, $classProperties); + $this->processCssSelector($selector, $classProperties, $important); } } @@ -315,9 +333,10 @@ private function processRule($selectors, $declarations) * * @param string $written Selector string, as written * @param array $classProperties CSS properties + * @param array $important The properties its !important declarations set, which only standard mode reads apart * @return void */ - private function processCssSelector($written, $classProperties) + private function processCssSelector($written, $classProperties, array $important) { $selector = strtoupper($written); @@ -337,10 +356,8 @@ private function processCssSelector($written, $classProperties) $level = count($tags); if (trim($tags[0]) === '@PAGE') { $tag = $this->selectorParser->parsePageSelector($tags); - if ($tag && isset($this->css[$tag])) { - $this->css[$tag] = Arrays::uniqueRecursiveMerge($this->css[$tag], $classProperties); - } elseif ($tag) { - $this->css[$tag] = $classProperties; + if ($tag) { + $this->storeByKey($tag, $classProperties, $important); } return; @@ -352,11 +369,12 @@ private function processCssSelector($written, $classProperties) // Legacy mode applies simple rules from these keys, and standard mode keeps them for what reads // CssManager::$CSS directly: BODY, and SVG's classes if ($simple) { - $this->storeSimpleRule($tag, $classProperties); + $this->storeByKey($tag, $classProperties, $important); + $this->indexStoredKey($tag); } if ($this->mpdf->cssMode === CssMode::STANDARD) { - $this->compileRule($written, $classProperties); + $this->compileRule($written, $classProperties, $important); return; } @@ -382,21 +400,20 @@ private function processCssSelector($written, $classProperties) } /** - * Stores a rule whose selector is one compound the legacy parser reads, under its key + * Stores a rule under its key: an @page rule, or one whose selector is one compound the legacy parser reads * - * @param string $key A key SelectorParser::parseSimpleSelector() made, e.g. P or CLASS>>A + * @param string $key A key SelectorParser made, e.g. P, CLASS>>A or @PAGE * @param array $classProperties + * @param array $important The properties its !important declarations set * @return void */ - private function storeSimpleRule($key, array $classProperties) + private function storeByKey($key, array $classProperties, array $important) { - if (isset($this->css[$key])) { - $this->css[$key] = Arrays::uniqueRecursiveMerge($this->css[$key], $classProperties); - } else { - $this->css[$key] = $classProperties; - } + $this->css[$key] = Arrays::uniqueRecursiveMerge(isset($this->css[$key]) ? $this->css[$key] : [], $classProperties); - $this->indexStoredKey($key); + if ($important) { + $this->importantCss[$key] = Arrays::uniqueRecursiveMerge(isset($this->importantCss[$key]) ? $this->importantCss[$key] : [], $important); + } } /** @@ -443,11 +460,12 @@ private function isLegacySelector(array $levels) * * @param string $selector As written * @param array $classProperties + * @param array $important The properties its !important declarations set * @return void */ - private function compileRule($selector, array $classProperties) + private function compileRule($selector, array $classProperties, array $important) { - if (!$classProperties) { + if (!$classProperties && !$important) { return; } @@ -455,7 +473,7 @@ private function compileRule($selector, array $classProperties) // The universal selector changes which elements existing documents style, so it waits for #530 if ($compiled !== null && !$compiled['universal']) { - $this->compiledRules[] = [$compiled, $classProperties]; + $this->compiledRules[] = [$compiled, $classProperties, $important]; } } @@ -466,6 +484,32 @@ private function compileRule($selector, array $classProperties) * @return array Associative array of CSS properties */ public function parseCssProperties($rawStyles) + { + return $this->inlineStyleParser->parseDeclarations($this->declarationsOf($rawStyles)); + } + + /** + * The properties the normal declarations of a block set, and those its !important ones set. Legacy mode reads a + * declaration marked !important as any other + * + * @param string $rawStyles The declarations of a block, with its comments removed + * @return array[] [normal properties, important properties] + */ + private function parseCssPropertiesByImportance($rawStyles) + { + if ($this->mpdf->cssMode === CssMode::STANDARD) { + return $this->inlineStyleParser->parseDeclarationsByImportance($this->declarationsOf($rawStyles)); + } + + return [$this->parseCssProperties($rawStyles), []]; + } + + /** + * @param string $rawStyles The declarations of a block, with its comments removed + * @return string[][] Each [name, value], with the whitespace in the value read as spaces and its data URI images + * stored + */ + private function declarationsOf($rawStyles) { $declarations = $this->tokenizer->declarations($rawStyles); foreach ($declarations as &$declaration) { @@ -479,7 +523,7 @@ public function parseCssProperties($rawStyles) } unset($declaration); - return $this->inlineStyleParser->parseDeclarations($declarations); + return $declarations; } /** diff --git a/src/Css/InlineStyleParser.php b/src/Css/InlineStyleParser.php index 25d7b3447..3781f9300 100644 --- a/src/Css/InlineStyleParser.php +++ b/src/Css/InlineStyleParser.php @@ -24,7 +24,7 @@ public function __construct(NormalizeProperties $normalizeProperties) * Parse inline CSS style attribute. * * Parses a CSS string from an HTML style attribute and returns - * an array of CSS properties. + * an array of CSS properties. A declaration marked !important is read as any other. * * @param string $html CSS string from style attribute * @return array Parsed CSS properties @@ -35,17 +35,61 @@ public function parse($html) } /** - * The properties a list of declarations sets, whether from a style attribute or a stylesheet's block + * Parse an HTML style attribute into the properties its normal declarations set and those its !important ones set + * + * @param string $html CSS string from style attribute + * @return array[] [normal properties, important properties] + */ + public function parseByImportance($html) + { + return $this->parseDeclarationsByImportance($this->tokenizer->declarations(htmlspecialchars_decode($html))); + } + + /** + * The properties a list of declarations sets, whether from a style attribute or a stylesheet's block. A + * declaration marked !important is read as any other * * @param string[][] $declarations Each [name, value], as StylesheetTokenizer::declarations() gives them * @return array Parsed CSS properties */ public function parseDeclarations(array $declarations) { - $classproperties = []; + $values = $this->valuesByImportance($declarations, false); + + return $this->normalizeProperties->normalize($values[0]); + } + + /** + * The properties the normal declarations of a list set, and those its !important ones set. Each set is normalised + * on its own, so a shorthand marked !important expands into longhands that are all important + * + * @param string[][] $declarations Each [name, value], as StylesheetTokenizer::declarations() gives them + * @return array[] [normal properties, important properties] + */ + public function parseDeclarationsByImportance(array $declarations) + { + $values = $this->valuesByImportance($declarations, true); + + return [ + $this->normalizeProperties->normalize($values[0]), + $this->normalizeProperties->normalize($values[1]), + ]; + } + + /** + * The value each declaration of a list gives its property, without !important, before the values are normalised + * + * @param string[][] $declarations Each [name, value], as StylesheetTokenizer::declarations() gives them + * @param bool $split Whether the declarations marked !important are kept apart from the others + * @return array[] [values of the normal declarations, values of the important ones], each keyed by the uppercased + * property. Unless split, every declaration is in the first + */ + private function valuesByImportance(array $declarations, $split) + { + $values = [[], []]; foreach ($declarations as $declaration) { $property = strtoupper(trim($declaration[0], " \t\n\r\0\x0B\f")); - $value = trim(preg_replace('/\s*!important/i', '', $this->processUrlsInCss($declaration[1]))); + $value = trim(preg_replace('/\s*!\s*important\b/i', '', $this->processUrlsInCss($declaration[1]), -1, $important)); if (empty($property) || $value === '') { continue; @@ -62,11 +106,12 @@ public function parseDeclarations(array $declarations) } // A repeated property moves to its last place, so it is expanded after a shorthand written before it - unset($classproperties[$property]); - $classproperties[$property] = $value; + $set = $split && $important ? 1 : 0; + unset($values[$set][$property]); + $values[$set][$property] = $value; } - return $this->normalizeProperties->normalize($classproperties); + return $values; } /** diff --git a/src/Css/RuleSet.php b/src/Css/RuleSet.php index a67713c39..5dfebe526 100644 --- a/src/Css/RuleSet.php +++ b/src/Css/RuleSet.php @@ -12,7 +12,7 @@ class RuleSet /** * @var array[] Each rule, by its position in the stylesheets read: [compiled selector, declarations, the ancestors - * it requires as requiredAncestors() gives them] + * it requires as requiredAncestors() gives them, !important declarations] */ private $rules = []; @@ -40,11 +40,12 @@ public function __construct() * * @param array $selector A selector SelectorCompiler::compile() compiled * @param array $declarations Its normalised declarations + * @param array $important Its normalised !important declarations */ - public function add(array $selector, array $declarations) + public function add(array $selector, array $declarations, array $important = []) { $position = count($this->rules); - $this->rules[] = [$selector, $declarations, self::requiredAncestors($selector)]; + $this->rules[] = [$selector, $declarations, self::requiredAncestors($selector), $important]; self::file($this->index, $selector['compounds'][count($selector['compounds']) - 1], $position); } @@ -65,7 +66,8 @@ public function candidates($tag, $id, array $classes) } /** - * The declarations of the rules an element matches, in the order they apply: by specificity, then by position + * The declarations of the rules an element matches, in the order they apply: by specificity, then by position. + * The normal declarations and the !important ones are given apart, as they apply in different layers * * @param string $tag Uppercased * @param string $id Uppercased, or empty for none @@ -73,18 +75,18 @@ public function candidates($tag, $id, array $classes) * @param callable $path Gives the open elements from the document down to the element, or null for none. Only * called when a rule is filed under the element * - * @return array[] + * @return array[] [the normal declarations of each rule, the !important declarations of each rule with any] */ public function matchingDeclarations($tag, $id, array $classes, callable $path) { $candidates = $this->candidates($tag, $id, $classes); if (!$candidates) { - return []; + return [[], []]; } $path = call_user_func($path); if ($path === null || $path[count($path) - 1]['tag'] !== $tag) { - return []; + return [[], []]; } $ancestors = self::ancestorsOf($path); @@ -112,9 +114,12 @@ public function matchingDeclarations($tag, $id, array $classes, callable $path) return $a - $b; }); - $declarations = []; + $declarations = [[], []]; foreach ($matched as $position) { - $declarations[] = $this->rules[$position][1]; + $declarations[0][] = $this->rules[$position][1]; + if ($this->rules[$position][3]) { + $declarations[1][] = $this->rules[$position][3]; + } } return $declarations; @@ -123,7 +128,8 @@ public function matchingDeclarations($tag, $id, array $classes, callable $path) /** * @param int $position * - * @return array The rule at a position, as it is kept: [compiled selector, declarations, required ancestors] + * @return array The rule at a position, as it is kept: [compiled selector, declarations, required ancestors, + * !important declarations] */ public function rule($position) { diff --git a/src/CssManager.php b/src/CssManager.php index 02a17fff1..78b64cb95 100644 --- a/src/CssManager.php +++ b/src/CssManager.php @@ -97,6 +97,17 @@ class CssManager */ private $defaultRules; + /** + * @var array[] The properties the !important declarations of the document's stylesheets set, under the keys of + * $CSS. Only standard mode reads them apart + */ + private $importantCss = []; + + /** + * @var array[] The properties the !important declarations of the default stylesheet set, under the keys of $CSS + */ + private $defaultImportantCss = []; + /** * CssManager constructor. * @@ -127,7 +138,7 @@ public function __construct(CssParser $cssParser, CssMerger $cssMerger) */ public function readCss($html) { - return $this->read($html, $this->rules); + return $this->read($html, $this->rules, $this->importantCss); } /** @@ -139,17 +150,22 @@ public function readCss($html) */ public function readDefaultCss($css) { - $this->read('', $this->defaultRules); + $this->read('', $this->defaultRules, $this->defaultImportantCss); } /** * Parse the CSS in HTML content into the stores readCss() describes, and file its compiled rules in a rule set * + * The !important declarations of the rules stored by key are kept apart as well, and laid again over $CSS after + * each read, those of the default stylesheet last, so that what reads $CSS directly (@page, BODY, SVG's classes) + * finds them over any declaration that is not important. + * * @param string $html * @param RuleSet $rules + * @param array $important Where the !important declarations of the rules stored by key go * @return string HTML with CSS content removed */ - private function read($html, RuleSet $rules) + private function read($html, RuleSet $rules, array &$important) { if (!is_array($this->cascadeCSS)) { $this->cascadeCSS = []; @@ -160,13 +176,36 @@ private function read($html, RuleSet $rules) $this->CSS = Arrays::uniqueRecursiveMerge($this->CSS, $this->cssParser->getCss()); $this->cascadeCSS = Arrays::uniqueRecursiveMerge($this->cascadeCSS, $this->cssParser->getCascadeCss()); + $important = Arrays::uniqueRecursiveMerge($important, $this->cssParser->getImportantCss()); + $this->CSS = Arrays::uniqueRecursiveMerge($this->CSS, $this->importantCss, $this->defaultImportantCss); + foreach ($this->cssParser->getCompiledRules() as $rule) { - $rules->add($rule[0], $rule[1]); + $rules->add($rule[0], $rule[1], $rule[2]); } return $html; } + /** + * The properties the !important declarations of the document's rules stored by key in $CSS set, such as BODY's + * + * @return array[] Under the keys of $CSS + */ + public function getImportantCss() + { + return $this->importantCss; + } + + /** + * The properties the !important declarations of the default stylesheet's rules stored by key in $CSS set + * + * @return array[] Under the keys of $CSS + */ + public function getDefaultImportantCss() + { + return $this->defaultImportantCss; + } + /** * The rules compiled for the matcher, from every stylesheet read so far * diff --git a/src/Mpdf.php b/src/Mpdf.php index a7f08d4bf..523cbd879 100644 --- a/src/Mpdf.php +++ b/src/Mpdf.php @@ -14467,6 +14467,7 @@ function WriteHTML($html, $mode = HTMLParserMode::DEFAULT_MODE, $init = true, $c } $zproperties = []; + $bodyAttr = []; if ($mode === HTMLParserMode::DEFAULT_MODE || $mode === HTMLParserMode::HEADER_CSS) { $this->ReadMetaTags($html); @@ -14491,7 +14492,13 @@ function WriteHTML($html, $mode = HTMLParserMode::DEFAULT_MODE, $init = true, $c $html = $m[2]; // Changed to allow style="background: url('bg.jpg')" if (preg_match('/style=[\"](.*?)[\"]/ism', $m[1], $mm) || preg_match('/style=[\'](.*?)[\']/ism', $m[1], $mm)) { - $zproperties = $this->cssManager->readInlineCSS($mm[1]); + if ($this->cssMode === CssMode::STANDARD) { + // Merged as an element's style is, so the !important declarations of a body rule beat it + $bodyAttr['STYLE'] = $mm[1]; + $zproperties = []; + } else { + $zproperties = $this->cssManager->readInlineCSS($mm[1]); + } } if (preg_match('/dir=[\'\"]\s*rtl\s*[\'\"]/ism', $m[1])) { $zproperties['DIRECTION'] = 'rtl'; @@ -14507,7 +14514,7 @@ function WriteHTML($html, $mode = HTMLParserMode::DEFAULT_MODE, $init = true, $c } } } - $properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', ''); + $properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', $bodyAttr); if ($zproperties) { $properties = Arrays::uniqueRecursiveMerge($properties, $zproperties); } diff --git a/tests/Mpdf/Css/CssParserTest.php b/tests/Mpdf/Css/CssParserTest.php index 6143406df..ef17ed9e6 100644 --- a/tests/Mpdf/Css/CssParserTest.php +++ b/tests/Mpdf/Css/CssParserTest.php @@ -324,6 +324,40 @@ public function testCompilesEveryRuleUnderTheStandardCascade() $this->assertSame([], $this->parser->getCascadeCss()); } + /** + * Under the standard cascade each rule keeps its !important declarations apart from the others, compiled and + * under the key of a rule stored by key, @page rules included + */ + public function testKeepsImportantDeclarationsApartUnderTheStandardCascade() + { + $this->mpdf->cssMode = CssMode::STANDARD; + $this->parser->parse(''); + + $rules = $this->parser->getCompiledRules(); + $this->assertCount(3, $rules); + $this->assertSame(['MARGIN-TOP' => '1mm', 'MARGIN-RIGHT' => '1mm', 'MARGIN-BOTTOM' => '1mm', 'MARGIN-LEFT' => '1mm'], $rules[0][1]); + $this->assertSame(['COLOR' => 'red'], $rules[0][2]); + $this->assertSame([], $rules[1][1]); + $this->assertSame(['FONT-SIZE' => '9pt'], $rules[1][2]); + $this->assertSame(['COLOR' => 'blue'], $rules[2][2]); + + $this->assertSame(['MARGIN-TOP' => '1mm', 'MARGIN-RIGHT' => '1mm', 'MARGIN-BOTTOM' => '1mm', 'MARGIN-LEFT' => '1mm'], $this->parser->getCss()['P']); + $this->assertSame([], $this->parser->getCss()['@PAGE']); + $this->assertSame(['P' => ['COLOR' => 'blue'], '@PAGE' => ['MARGIN-LEFT' => '1cm']], $this->parser->getImportantCss()); + } + + /** + * Under the legacy cascade a declaration marked !important is stored with the others, and the one after it + * replaces it + */ + public function testReadsTheFlagAsNothingUnderTheLegacyCascade() + { + $this->parser->parse(''); + + $this->assertSame(['COLOR' => 'green', 'MARGIN-TOP' => '1mm'], $this->parser->getCss()['P']); + $this->assertSame([], $this->parser->getImportantCss()); + } + /** * Each at-rule is unwrapped, kept or left out whole, in either cssMode, and the rules around it are stored as * they are written diff --git a/tests/Mpdf/Css/InlineStyleParserTest.php b/tests/Mpdf/Css/InlineStyleParserTest.php index 7c72f6c0b..bc836baf6 100644 --- a/tests/Mpdf/Css/InlineStyleParserTest.php +++ b/tests/Mpdf/Css/InlineStyleParserTest.php @@ -240,6 +240,80 @@ public function importantDeclarations() ]; } + /** + * The declarations marked !important are parsed apart from the others, each set on its own, so a shorthand marked + * important gives important longhands, and a later declaration that is not important takes nothing from it + * + * @dataProvider declarationsByImportance + * + * @param string $style + * @param array $normal The properties of the declarations not marked + * @param array $important The properties of those marked !important + */ + public function testParseByImportanceKeepsTheImportantDeclarationsApart($style, array $normal, array $important) + { + $this->assertSame([$normal, $important], $this->inlineStyleParser->parseByImportance($style)); + } + + /** + * Style attributes with declarations marked !important in various ways, and the two sets of properties each gives + * + * @return array[] + */ + public function declarationsByImportance() + { + return [ + 'none marked' => ['color: #f00', ['COLOR' => '#f00'], []], + 'all marked' => ['color: #f00 !important', [], ['COLOR' => '#f00']], + 'the flag in capitals, spaced from the bang' => ['color: #f00 ! IMPORTANT', [], ['COLOR' => '#f00']], + 'the flag against the value, in mixed case' => ['color: #f00!Important', [], ['COLOR' => '#f00']], + 'a later declaration not marked' => [ + 'color: #0f0 !important; color: #f00', + ['COLOR' => '#f00'], + ['COLOR' => '#0f0'], + ], + 'two marked, the later winning' => ['color: #f00 !important; color: #0f0 !important', [], ['COLOR' => '#0f0']], + 'a marked shorthand and a later longhand' => [ + 'padding: 1mm 2mm !important; padding-top: 5mm', + ['PADDING-TOP' => '5mm'], + ['PADDING-TOP' => '1mm', 'PADDING-RIGHT' => '2mm', 'PADDING-BOTTOM' => '1mm', 'PADDING-LEFT' => '2mm'], + ], + 'a marked border shorthand' => [ + 'border-top-color: #00f; border: 1px solid #f00 !important', + ['BORDER-TOP-COLOR' => '#00f'], + [ + 'BORDER-TOP' => '1px solid #f00', + 'BORDER-TOP-WIDTH' => '1px', + 'BORDER-TOP-STYLE' => 'solid', + 'BORDER-TOP-COLOR' => '#f00', + 'BORDER-RIGHT' => '1px solid #f00', + 'BORDER-RIGHT-WIDTH' => '1px', + 'BORDER-RIGHT-STYLE' => 'solid', + 'BORDER-RIGHT-COLOR' => '#f00', + 'BORDER-BOTTOM' => '1px solid #f00', + 'BORDER-BOTTOM-WIDTH' => '1px', + 'BORDER-BOTTOM-STYLE' => 'solid', + 'BORDER-BOTTOM-COLOR' => '#f00', + 'BORDER-LEFT' => '1px solid #f00', + 'BORDER-LEFT-WIDTH' => '1px', + 'BORDER-LEFT-STYLE' => 'solid', + 'BORDER-LEFT-COLOR' => '#f00', + ], + ], + 'a marked value mPDF cannot read' => ['width: 50%; width: calc(100% - 1mm) !important', ['WIDTH' => '50%'], []], + ]; + } + + /** + * Parsed without keeping them apart, a declaration marked !important is read as any other: a later declaration + * of the property replaces it, as mPDF v7 read it + */ + public function testParseReadsTheFlagAsNothing() + { + $this->assertSame(['COLOR' => '#f00'], $this->inlineStyleParser->parse('color: #0f0 !important; color: #f00')); + $this->assertSame(['MARGIN-TOP' => '5mm', 'MARGIN-RIGHT' => '5mm', 'MARGIN-BOTTOM' => '5mm', 'MARGIN-LEFT' => '5mm'], $this->inlineStyleParser->parse('margin: 5mm ! important')); + } + /** * A declaration mPDF cannot read is dropped, so an earlier one of the same property in the attribute still applies */ diff --git a/tests/Mpdf/Css/RuleSetTest.php b/tests/Mpdf/Css/RuleSetTest.php index 52230f164..d543c8f53 100644 --- a/tests/Mpdf/Css/RuleSetTest.php +++ b/tests/Mpdf/Css/RuleSetTest.php @@ -129,6 +129,32 @@ public function testGivesTheMatchingDeclarationsBySpecificityThenPosition() $this->assertSame( [['COLOR' => 'rule 1'], ['COLOR' => 'rule 4'], ['COLOR' => 'rule 3'], ['COLOR' => 'rule 0'], ['COLOR' => 'rule 2'], ['COLOR' => 'rule 5']], + $rules->matchingDeclarations('P', '', [], $path)[0] + ); + } + + /** + * The !important declarations of the rules an element matches come apart from the others, in the same order, and + * only from the rules that have any + */ + public function testGivesTheImportantDeclarationsApartInTheSameOrder() + { + $rules = new RuleSet(); + $rules->add($this->compiler->compile('#main > p'), ['COLOR' => 'id'], ['FONT-SIZE' => 'id']); + $rules->add($this->compiler->compile('div > p'), ['COLOR' => 'first tag'], ['FONT-SIZE' => 'first tag']); + $rules->add($this->compiler->compile('p:first-child'), ['COLOR' => 'pseudo-class']); + $rules->add($this->compiler->compile('div > p'), [], ['FONT-SIZE' => 'second tag']); + $rules->add($this->compiler->compile('ul > p'), ['COLOR' => 'no match'], ['FONT-SIZE' => 'no match']); + + $path = function () { + return $this->path(); + }; + + $this->assertSame( + [ + [['COLOR' => 'first tag'], [], ['COLOR' => 'pseudo-class'], ['COLOR' => 'id']], + [['FONT-SIZE' => 'first tag'], ['FONT-SIZE' => 'second tag'], ['FONT-SIZE' => 'id']], + ], $rules->matchingDeclarations('P', '', [], $path) ); } @@ -145,13 +171,13 @@ public function testOnlyAsksForThePathWhenARuleIsFiledUnderTheElement() return null; }; - $this->assertSame([], $this->rules->matchingDeclarations('LI', '', [], $path)); + $this->assertSame([[], []], $this->rules->matchingDeclarations('LI', '', [], $path)); $this->assertTrue($asked, 'The rule for any element should ask'); $rules = new RuleSet(); $rules->add($this->compiler->compile('div > p'), ['COLOR' => 'red']); $asked = false; - $this->assertSame([], $rules->matchingDeclarations('LI', '', [], $path)); + $this->assertSame([[], []], $rules->matchingDeclarations('LI', '', [], $path)); $this->assertFalse($asked); } @@ -167,7 +193,7 @@ public function testMatchesNothingForThePathOfAnotherElement() return $this->path(); }; - $this->assertSame([], $rules->matchingDeclarations('SPAN', '', [], $path)); + $this->assertSame([[], []], $rules->matchingDeclarations('SPAN', '', [], $path)); } /** diff --git a/tests/Mpdf/CssManagerTest.php b/tests/Mpdf/CssManagerTest.php index 697888b20..b18279599 100644 --- a/tests/Mpdf/CssManagerTest.php +++ b/tests/Mpdf/CssManagerTest.php @@ -907,6 +907,39 @@ public function testKeepsTheCompiledRulesOfEveryStylesheetRead() $this->assertSame(['COLOR' => 'green'], $rules->rule($candidates[2])[1]); } + /** + * Under the standard cascade the !important declarations of rules stored by key are laid over CssManager::$CSS + * after every stylesheet read, so what reads it directly finds them over a later declaration that is not + * important, and those of the default stylesheet over the document's. Both are kept apart as well + */ + public function testLaysImportantDeclarationsOverTheStoredRules() + { + $this->mpdf->cssMode = CssMode::STANDARD; + $this->cssManager->readDefaultCss('body { color: gray !important; margin-top: 1mm; }'); + $this->cssManager->readCss(''); + $this->cssManager->readCss(''); + + $this->assertSame('gray', $this->cssManager->CSS['BODY']['COLOR']); + $this->assertSame('9pt', $this->cssManager->CSS['BODY']['FONT-SIZE']); + $this->assertSame('2mm', $this->cssManager->CSS['BODY']['MARGIN-TOP']); + $this->assertSame('5mm', $this->cssManager->CSS['@PAGE']['MARGIN-LEFT']); + $this->assertSame(['BODY' => ['COLOR' => 'red', 'FONT-SIZE' => '9pt'], '@PAGE' => ['MARGIN-LEFT' => '5mm']], $this->cssManager->getImportantCss()); + $this->assertSame(['BODY' => ['COLOR' => 'gray']], $this->cssManager->getDefaultImportantCss()); + } + + /** + * Under the legacy cascade a declaration marked !important is stored as any other, and a later one replaces it + */ + public function testStoresImportantDeclarationsAsAnyOtherUnderTheLegacyCascade() + { + $this->cssManager->readCss(''); + $this->cssManager->readCss(''); + + $this->assertSame('blue', $this->cssManager->CSS['BODY']['COLOR']); + $this->assertSame('9mm', $this->cssManager->CSS['@PAGE']['MARGIN-LEFT']); + $this->assertSame([], $this->cssManager->getImportantCss()); + } + /** * The default stylesheet's rules are kept apart from the document's, and a document's stylesheet never adds to them */ diff --git a/tests/Mpdf/ImportantContextTest.php b/tests/Mpdf/ImportantContextTest.php new file mode 100644 index 000000000..b52547cbe --- /dev/null +++ b/tests/Mpdf/ImportantContextTest.php @@ -0,0 +1,150 @@ + $subject) { + $expected[$text] = $subject[$cascade === CssMode::LEGACY ? 1 : 2]; + } + + $mpdf = $this->drawDocument($this->document($context, $css, $subjects), ['cssMode' => $cascade]); + $mpdf->OutputBinaryData(); + + $this->assertDrawnInColours($expected, $this->keyedByText($mpdf, $mpdf->drawnColours)); + $this->assertDrawnInContext($context, $mpdf, array_keys($expected)); + } + + /** + * Every case in every context, under each cascade + * + * @return array[] + */ + public function casesInContexts() + { + $data = []; + foreach ([CssMode::LEGACY, CssMode::STANDARD] as $cascade) { + foreach (['block', 'inline', 'table cell', 'header', 'footer', 'positioned block', 'kept block', 'forced page break'] as $context) { + foreach ($this->cases() as $name => $case) { + $data[$cascade . ', ' . $context . ': ' . $name] = [$cascade, $context, $case[0], $case[1]]; + } + } + } + + return $data; + } + + /** + * Rules with an important declaration, and the elements they are matched against. Every subject is inside an + * element of class w + * + * @return array[] Each [css, subjects]: each subject keyed by its text, with its attributes, the colour the legacy + * cascade draws it in, as measured, and the colour the standard cascade draws it in + */ + private function cases() + { + return [ + 'an important class beats an id' => [ + '.c { color: #008000 !important; } #i { color: #f00; }', + ['both' => ['id="i" class="c"', self::RED, self::GREEN], 'id only' => ['id="i"', self::RED, self::RED]], + ], + 'an important rule beats the inline style' => [ + '.c { color: #008000 !important; }', + ['both' => ['class="c" style="color: #f00"', self::RED, self::GREEN], 'inline only' => ['style="color: #f00"', self::RED, self::RED]], + ], + 'an important inline style beats an important rule' => [ + '#i { color: #f00 !important; }', + [ + 'important inline' => ['id="i" style="color: #008000 !important"', self::GREEN, self::GREEN], + 'plain inline' => ['id="i" style="color: #00f"', self::BLUE, self::RED], + ], + ], + 'the more specific of two important rules wins' => [ + '.c.d { color: #008000 !important; } {T}.c { color: #f00 !important; }', + ['both' => ['class="c d"', self::RED, self::GREEN], 'one class' => ['class="c"', self::RED, self::RED]], + ], + 'the later of two important rules as specific wins' => [ + '.b { color: #f00 !important; } .a { color: #008000 !important; } .b { color: #00f; }', + ['b then a' => ['class="b a"', self::BLUE, self::GREEN], 'b alone' => ['class="b"', self::BLUE, self::RED]], + ], + 'an important descendant rule beats an id' => [ + '.w {T}.c { color: #008000 !important; } #i { color: #f00; }', + ['both' => ['id="i" class="c"', self::GREEN, self::GREEN], 'id only' => ['id="i"', self::RED, self::RED]], + ], + 'an important rule in a matching @media' => [ + '@media print { .c { color: #008000 !important; } } @media screen { .c { color: #00f !important; } } #i { color: #f00; }', + ['both' => ['id="i" class="c"', self::RED, self::GREEN], 'id only' => ['id="i"', self::RED, self::RED]], + ], + 'the flag in capitals, spaced from the bang' => [ + '.c { color: #008000 ! IMPORTANT; } #i { color: #f00; }', + ['both' => ['id="i" class="c"', self::RED, self::GREEN], 'id only' => ['id="i"', self::RED, self::RED]], + ], + 'an important declaration beats a later one of its block' => [ + '.c { color: #008000 !important; color: #f00; }', + ['with the class' => ['class="c"', self::RED, self::GREEN], 'without it' => ['', self::BLACK, self::BLACK]], + ], + ]; + } + + /** + * A document with each subject inside an element of class w, in a context, under a stylesheet naming the tag the + * context gives them + * + * @param string $context + * @param string $css With {T} for the subjects' tag + * @param array[] $subjects As cases() gives them + * + * @return string + */ + private function document($context, $css, array $subjects) + { + $tag = $context === 'inline' ? 'em' : ($context === 'table cell' ? 'td' : 'p'); + + $html = ''; + foreach ($subjects as $text => $subject) { + $html .= '<' . $tag . ' ' . $subject[0] . '>' . $text . ' '; + } + + if ($context === 'inline') { + $html = '

' . $html . '

'; + } elseif ($context === 'table cell') { + $html = '' . $html . '
'; + } + + $html = '
' . $html . '
'; + + // A table cell and an inline element are the subjects' own tags, in the flow + return '' . ($context === 'table cell' ? $html : $this->inContext($context, $html)); + } +} diff --git a/tests/Mpdf/ImportantDeclarationTest.php b/tests/Mpdf/ImportantDeclarationTest.php new file mode 100644 index 000000000..c1969723f --- /dev/null +++ b/tests/Mpdf/ImportantDeclarationTest.php @@ -0,0 +1,405 @@ + $expected Pieces of text and the colour each should be drawn in + */ + public function testAppliesImportantDeclarationsInTheCascadesOrder($cascade, $css, $html, array $expected) + { + $this->assertDrawnInColours($expected, $this->drawnColours('' . $html, ['cssMode' => $cascade])); + } + + /** + * Each row of precedenceTable() once for each cascade, with that cascade's colours + * + * @return array[] + */ + public function precedence() + { + $cases = []; + foreach ($this->precedenceTable() as $name => $row) { + list($css, $html, $legacy, $standard) = $row; + $cases[$name . ' (legacy)'] = [CssMode::LEGACY, $css, $html, $legacy]; + $cases[$name . ' (standard)'] = [CssMode::STANDARD, $css, $html, $standard]; + } + + return $cases; + } + + /** + * Rules that compete for an element's colour with at least one declaration marked !important, a document with an + * element each rule reaches and a near miss only one of them reaches, and the colours its text is drawn in by the + * legacy cascade, as measured, and by the standard cascade, as CSS Cascade gives them + * + * @return array[] Each [css, html, legacy colours, standard colours] + */ + private function precedenceTable() + { + return [ + 'an important class beats an id' => [ + '.c { color: #008000 !important; } #i { color: #f00; }', + '

both

id only

', + ['both' => self::RED, 'id only' => self::RED], + ['both' => self::GREEN, 'id only' => self::RED], + ], + 'an important tag beats an id' => [ + 'p { color: #008000 !important; } #i { color: #f00; }', + '

p with the id

div with the id
', + ['p with the id' => self::RED, 'div with the id' => self::RED], + ['p with the id' => self::GREEN, 'div with the id' => self::RED], + ], + 'an important rule beats the inline style' => [ + '.c { color: #008000 !important; }', + '

both

inline only

', + ['both' => self::RED, 'inline only' => self::RED], + ['both' => self::GREEN, 'inline only' => self::RED], + ], + 'an important inline style beats an important rule' => [ + '#i { color: #f00 !important; }', + '

important inline

plain inline

rule only

', + ['important inline' => self::GREEN, 'plain inline' => self::BLUE, 'rule only' => self::RED], + ['important inline' => self::GREEN, 'plain inline' => self::RED, 'rule only' => self::RED], + ], + 'an important declaration beats a later one of the block that is not' => [ + '.c { color: #008000 !important; color: #f00; }', + '

class

', + ['class' => self::RED], + ['class' => self::GREEN], + ], + 'an important inline declaration beats a later one of the style that is not' => [ + '', + '

inline

', + ['inline' => self::RED], + ['inline' => self::GREEN], + ], + 'the more specific of two important rules wins' => [ + '.c.d { color: #008000 !important; } p.c { color: #f00 !important; }', + '

both

one class

', + ['both' => self::RED, 'one class' => self::RED], + ['both' => self::GREEN, 'one class' => self::RED], + ], + 'the later of two important rules as specific wins' => [ + '.b { color: #f00 !important; } .a { color: #008000 !important; } .b { color: #00f; }', + '

b a

b only

', + ['b a' => self::BLUE, 'b only' => self::BLUE], + ['b a' => self::GREEN, 'b only' => self::RED], + ], + 'an important rule of a later stylesheet wins at the same specificity' => [ + '.a { color: #008000 !important; } ' . $html, ['cssMode' => $cascade, 'mode' => 'c']))[0]; + + foreach ($drawn as $operator) { + $this->assertStringContainsString($operator, $page); + } + foreach ($notDrawn as $operator) { + $this->assertStringNotContainsString($operator, $page); + } + } + + /** + * The border and background shorthands against longhands of a more specific rule, and of the same block after + * them, under each cascade + * + * @return array[] + */ + public function shorthands() + { + $green = '0.000 0.502 0.000 RG'; + $red = '1.000 0.000 0.000 RG'; + $greenFill = '0.000 0.502 0.000 rg'; + $redFill = '1.000 0.000 0.000 rg'; + + $border = '.c { border: 1mm solid #008000 !important; border-top-color: #f00; } #i { border-bottom-color: #f00; border-left: 1mm solid #f00; }'; + $background = '.c { background: #008000 !important; } #i { background-color: #f00; }'; + + return [ + 'border (legacy)' => [CssMode::LEGACY, $border, '
boxed
', [$green, $red], []], + 'border (standard)' => [CssMode::STANDARD, $border, '
boxed
', [$green], [$red]], + 'border of an inline element (standard)' => [CssMode::STANDARD, $border, '

boxed

', [$green], [$red]], + 'border of a table cell (standard)' => [CssMode::STANDARD, $border, '
boxed
', [$green], [$red]], + 'background (legacy)' => [CssMode::LEGACY, $background, '
filled
', [$redFill], [$greenFill]], + 'background (standard)' => [CssMode::STANDARD, $background, '
filled
', [$greenFill], [$redFill]], + 'background of a table cell (standard)' => [CssMode::STANDARD, $background, '
filled
', [$greenFill], [$redFill]], + ]; + } + + /** + * The font shorthand marked !important sets the size over a more specific rule's, and the weight it resets to + * normal: the text is drawn at 14pt in Times Roman. The legacy cascade applies the id's 10pt bold + * + * @dataProvider cascades + * + * @param string $cascade + * @param float $size The size the text is drawn at + * @param string $font The core font it is drawn in + */ + public function testAnImportantFontShorthandExpandsWithItsFlag($cascade, $size, $font) + { + $html = '

text

'; + + $this->assertEquals($size, $this->drawDocument($html, ['cssMode' => $cascade])->drawnFontSize[0]); + $this->assertStringContainsString('/BaseFont /' . $font, $this->render($html, ['cssMode' => $cascade, 'mode' => 'c'])); + } + + /** + * Each cascade with the font size and core font the text is drawn in + * + * @return array[] + */ + public function cascades() + { + return [ + CssMode::LEGACY => [CssMode::LEGACY, 10, 'Times-Bold'], + CssMode::STANDARD => [CssMode::STANDARD, 14, 'Times-Roman'], + ]; + } + + /** + * The important declarations of the default stylesheet beat the document's, of its stylesheets and its inline + * styles alike, as a user agent's do an author's. Its declarations that are not important lose to the document's. + * The legacy cascade reads the default stylesheet first and the flag as nothing, so the document wins + * + * @dataProvider defaultStylesheet + * + * @param string $cascade + * @param array $colours + * @param float $size The font size the body is drawn at + */ + public function testTheDefaultStylesheetsImportantDeclarationsComeLast($cascade, array $colours, $size) + { + $mpdf = $this->drawDocument( + '' + . '

default rule

document rule

plain default rule

', + ['cssMode' => $cascade, 'defaultCssFile' => __DIR__ . '/../data/css/important-default.css'] + ); + + $this->assertDrawnInColours($colours, $this->keyedByText($mpdf, $mpdf->drawnColours)); + $this->assertEquals($size, $mpdf->drawnFontSize[0]); + } + + /** + * Each cascade, the colours it draws each paragraph in, and the font size of the body + * + * @return array[] + */ + public function defaultStylesheet() + { + return [ + CssMode::LEGACY => [CssMode::LEGACY, ['default rule' => self::BLUE, 'document rule' => self::RED, 'plain default rule' => self::GREEN], 8], + CssMode::STANDARD => [CssMode::STANDARD, ['default rule' => self::GREEN, 'document rule' => self::RED, 'plain default rule' => self::GREEN], 9], + ]; + } + + /** + * An important declaration of a body rule beats the style attribute of the body, and an important one of the + * style attribute beats both + * + * @dataProvider bodies + * + * @param string $cascade + * @param string $css + * @param string $style The body's style attribute + * @param string $expected The colour the text is drawn in + */ + public function testTheBodysStyleMeetsImportantBodyRules($cascade, $css, $style, $expected) + { + $colours = $this->drawnColours('

text

', ['cssMode' => $cascade]); + + $this->assertSame($expected, $colours['text']); + } + + /** + * Each cascade with a body rule and a style attribute, one of them marked important + * + * @return array[] + */ + public function bodies() + { + $rule = 'body { color: #008000 !important; }'; + $style = 'color: #008000 !important'; + + return [ + 'an important rule (legacy)' => [CssMode::LEGACY, $rule, 'color: #f00', self::RED], + 'an important rule (standard)' => [CssMode::STANDARD, $rule, 'color: #f00', self::GREEN], + 'an important rule against an important style (legacy)' => [CssMode::LEGACY, 'body { color: #f00 !important; }', $style, self::GREEN], + 'an important rule against an important style (standard)' => [CssMode::STANDARD, 'body { color: #f00 !important; }', $style, self::GREEN], + 'a plain rule against a plain style (standard)' => [CssMode::STANDARD, 'body { color: #f00; }', 'color: #008000', self::GREEN], + ]; + } + + /** + * An important declaration of an @page rule beats a later one that is not, under the standard cascade + * + * @dataProvider pageMargins + * + * @param string $cascade + * @param float $left The left margin of the page + */ + public function testAnImportantPageRuleBeatsALaterOne($cascade, $left) + { + $mpdf = $this->drawDocument('

text

', ['cssMode' => $cascade]); + + $this->assertEqualsWithDelta($left, $mpdf->drawnBoxes[0][1], 0.01); + } + + /** + * Each cascade with the left margin it gives the page + * + * @return array[] + */ + public function pageMargins() + { + return [ + CssMode::LEGACY => [CssMode::LEGACY, 10], + CssMode::STANDARD => [CssMode::STANDARD, 50], + ]; + } + + /** + * An important declaration of a class rule beats a later one that is not in the text of an SVG, which looks its + * classes up in CssManager::$CSS + * + * @dataProvider svgFills + * + * @param string $cascade + * @param string $fill The fill operator the text is drawn with + */ + public function testAnImportantClassRuleFillsSvgText($cascade, $fill) + { + $svg = 'Hi'; + $html = ''; + + $this->assertStringContainsString($fill, $this->render($html, ['cssMode' => $cascade, 'svgClasses' => true])); + } + + /** + * Each cascade with the fill it gives the SVG's text + * + * @return array[] + */ + public function svgFills() + { + return [ + CssMode::LEGACY => [CssMode::LEGACY, '1.000 0.000 0.000 rg'], + CssMode::STANDARD => [CssMode::STANDARD, '0.000 1.000 0.000 rg'], + ]; + } + + /** + * An important cell rule sets the border dominance of the sides it gives a border, as every cell rule does, and an + * important inline style of a cell does too + * + * @dataProvider cellBorders + * + * @param string $cascade + * @param string $html A table left open in a cell given a left border + */ + public function testAnImportantCellBorderTakesACellRulesDominance($cascade, $html) + { + $mpdf = new Mpdf(['mode' => 'c', 'cssMode' => $cascade]); + $mpdf->WriteHTML($html, HTMLParserMode::DEFAULT_MODE, true, false); + + $manager = new \ReflectionProperty($mpdf, 'cssManager'); + if (PHP_VERSION_ID < 80100) { + $manager->setAccessible(true); + } + + $this->assertSame(9, $manager->getValue($mpdf)->getBorderDominance('L')); + $this->assertSame(0, $manager->getValue($mpdf)->getBorderDominance('R')); + } + + /** + * Each cascade with a cell whose left border comes from an important rule, and from an important inline style + * + * @return array[] + */ + public function cellBorders() + { + $rule = '
'; + $style = '
'; + + return [ + 'a rule (legacy)' => [CssMode::LEGACY, $rule], + 'a rule (standard)' => [CssMode::STANDARD, $rule], + 'an inline style (legacy)' => [CssMode::LEGACY, $style], + 'an inline style (standard)' => [CssMode::STANDARD, $style], + ]; + } +} diff --git a/tests/Snapshots/FrameworkImportantLegacySnapshotTest.php b/tests/Snapshots/FrameworkImportantLegacySnapshotTest.php new file mode 100644 index 000000000..37174e312 --- /dev/null +++ b/tests/Snapshots/FrameworkImportantLegacySnapshotTest.php @@ -0,0 +1,21 @@ +cascade(); + } + + /** + * The components, each under a caption saying what the standard and the legacy cascade draw + */ + public function generatePdf() + { + ob_start(); + ?> + + +

Framework utilities marked !important

+

Written with cssMode set to cascade(); ?>.

+ +

A utility against an id

+

.text-success and .fw-normal against #sidebar p. Standard: the first line is green and not bold, the utilities beating the id. Legacy: it is grey and bold like the second, the descendant rule coming last.

+ + +

A utility against the inline style

+

.text-success against style="color: grey". Standard: the first line is green. Legacy: it is grey like the second, the inline style coming last.

+

With the utility

+

Without it

+ +

An inline !important against a utility

+

style="color: green" against .text-muted, with and without !important. Both: the first line is green. Standard: the second line is grey, the utility beating the inline style that is not important. Legacy: it is green too.

+

Styled inline with !important

+

Styled inline without it

+ +

Two utilities

+

.text-success and .text-primary, both !important and as specific, .text-primary written later. Standard: the line is blue, the later rule winning. Legacy: it is green, classes applying in alphabetical order.

+

Both colour utilities

+ +

A spacing utility against a component

+

.m-0 against .card p. Standard: the first paragraph sits against the top of the card, with no margin. Legacy: it has the 4mm margin of the second, the descendant rule coming last.

+

With .m-0

Without it

+ +

Hidden by a utility

+

.d-none against #promo { display: block }. Standard: only "Visible alert" is drawn. Legacy: "Hidden alert" is drawn above it, the id coming last.

+
Hidden alert
+
Visible alert
+ +

Border and background utilities against an id

+

.border-0 and .bg-light (a background shorthand) against #notice. Standard: the notice has no border and a light grey background. Legacy: it has a thick dark red border and a pink background, the id coming last.

+
A notice
+ +

A utility in a table

+

.text-end against .table td. Standard: the amounts are right-aligned. Legacy: they are left-aligned, the descendant rule coming last.

+ + + + +
ItemAmount
Consulting1,200.00
Hosting300.00
+ +

A utility against a component inside an id

+

.bg-success against #checkout .btn. Standard: the first button is green. Legacy: it is purple like the second, the descendant rule coming last.

+

With .bg-success Without it

+ mpdf = $this->createMpdf(['cssMode' => $this->cascade()]); + + $this->mpdf->WriteHTML($html); + } + +} diff --git a/tests/Snapshots/FrameworkImportantStandardSnapshotTest.php b/tests/Snapshots/FrameworkImportantStandardSnapshotTest.php new file mode 100644 index 000000000..56245275e --- /dev/null +++ b/tests/Snapshots/FrameworkImportantStandardSnapshotTest.php @@ -0,0 +1,21 @@ + + + +

!important

+ +

.class !important beats #id: the line is green.

+

An important class against an id

+ +

.class !important beats the inline style: the line is green.

+

An important class against the inline style

+ +

An inline !important beats #id !important: the line is green.

+

An important inline style against an important id

+ +

An !important declaration beats one written after it in the same block: the line is green.

+

An important declaration against a later one

+ +

Of two !important rules, .class.class beats p.class: the line is green.

+

Two important rules of different specificity

+ +

Of two !important rules as specific, the one written later wins, and a plain rule after both does not: the line is green.

+

Two important rules as specific

+ +

An !important rule inside @media print beats #id, and one inside @media screen is left out: the line is green.

+

An important rule inside @media

+ +

The flag in capitals, spaced from the bang, still counts: the line is green.

+

! IMPORTANT

+ +

border: … !important expands into sides that are all important: a solid green border of even width on every side, no red, no dots.

+
An important border shorthand
+ +

background: … !important beats #id's background-color: a pale green background.

+
An important background shorthand
+ +

font: 13pt serif !important sets the size over #id's 7pt, and resets its bold: the line is large, serif and not bold.

+

An important font shorthand

+ +

td.class !important beats td#id on a collapsed border: the middle cell has a thick green border, drawn over its neighbours' thin red ones.

+
LeftMiddleRight
+ +

The default stylesheet's p.ua { color: green !important } beats the document's p.ua !important and an inline !important: the line is green.

+

An important rule of the default stylesheet

+ mpdf = $this->createMpdf(['cssMode' => \Mpdf\CssMode::STANDARD, 'defaultCssFile' => __DIR__ . '/../data/css/important-default.css']); + + $this->mpdf->WriteHTML($html); + } + +} diff --git a/tests/data/css/important-default.css b/tests/data/css/important-default.css new file mode 100644 index 000000000..cc1dc2768 --- /dev/null +++ b/tests/data/css/important-default.css @@ -0,0 +1,13 @@ +/* A default stylesheet with !important declarations, which beat the document's own under the standard cascade */ + +body { + font-size: 9pt !important; +} + +p.ua { + color: #008000 !important; +} + +p.plain { + color: #f00; +} diff --git a/tests/data/snapshots/framework-important-legacy.pdf b/tests/data/snapshots/framework-important-legacy.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7d6ad2fede25deaadf957595c06a629e48bf7a1f GIT binary patch literal 42666 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 MSP`hHrBtN<2U1lRj{pDw literal 0 HcmV?d00001 diff --git a/tests/data/snapshots/framework-important-standard.pdf b/tests/data/snapshots/framework-important-standard.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f1ebad610ea6cfd9ff3865ad7b08ced0c85623cc GIT binary patch literal 40704 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 m*Y3~`wI5te3 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 literal 0 HcmV?d00001 diff --git a/tests/data/snapshots/important-declarations.pdf b/tests/data/snapshots/important-declarations.pdf new file mode 100644 index 0000000000000000000000000000000000000000..16f11d88c8b7dc3cfeaa4de4767b20793ac0360f GIT binary patch literal 43625 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%0Ad@Ww7r26f^y9)W#V&|tB3n7 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