diff --git a/src/Mpdf.php b/src/Mpdf.php index 523b8b7d6..50c34355c 100644 --- a/src/Mpdf.php +++ b/src/Mpdf.php @@ -9497,7 +9497,7 @@ function SetDash($black = false, $white = false) function SetDisplayPreferences($preferences) { - // String containing any or none of /HideMenubar/HideToolbar/HideWindowUI/DisplayDocTitle/CenterWindow/FitWindow + // String containing any or none of /HideMenubar/HideToolbar/HideWindowUI/DisplayDocTitle/CenterWindow/FitWindow/NoPrintScaling/FullScreen/UseAttachments $this->DisplayPreferences .= $preferences; } diff --git a/src/Writer/MetadataWriter.php b/src/Writer/MetadataWriter.php index be9423fe6..330318ce4 100644 --- a/src/Writer/MetadataWriter.php +++ b/src/Writer/MetadataWriter.php @@ -379,12 +379,11 @@ public function writeCatalog() //_putcatalog // Bookmarks if (count($this->mpdf->BMoutlines) > 0) { $this->writer->write('/Outlines ' . $this->mpdf->OutlineRoot . ' 0 R'); - $this->writer->write('/PageMode /UseOutlines'); } - // Fullscreen - if (is_int(strpos($this->mpdf->DisplayPreferences, 'FullScreen'))) { - $this->writer->write('/PageMode /FullScreen'); + $pageMode = $this->getPageMode(); + if ($pageMode !== null) { + $this->writer->write('/PageMode /' . $pageMode); } // Metadata @@ -463,10 +462,6 @@ public function writeCatalog() //_putcatalog $this->writer->write('>>'); } - if ($this->mpdf->open_layer_pane && ($this->mpdf->hasOC || count($this->mpdf->layers))) { - $this->writer->write('/PageMode /UseOC'); - } - if ($this->mpdf->hasOC || count($this->mpdf->layers)) { $p = $v = $h = $l = $loff = $lall = $as = ''; @@ -510,6 +505,34 @@ public function writeCatalog() //_putcatalog } } + /** + * A catalog carries a single /PageMode, so the modes the document asks for explicitly take + * precedence over the outline pane implied by simply having bookmarks. + * + * @return string|null + */ + private function getPageMode() + { + if ($this->mpdf->open_layer_pane && ($this->mpdf->hasOC || count($this->mpdf->layers))) { + return 'UseOC'; + } + + if (is_int(strpos($this->mpdf->DisplayPreferences, 'FullScreen'))) { + return 'FullScreen'; + } + + // UseAttachments is PDF 1.6 spec. + if (is_int(strpos($this->mpdf->DisplayPreferences, 'UseAttachments'))) { + return 'UseAttachments'; + } + + if (count($this->mpdf->BMoutlines) > 0) { + return 'UseOutlines'; + } + + return null; + } + /** * @since 5.7.2 */ diff --git a/tests/Mpdf/PageModeTest.php b/tests/Mpdf/PageModeTest.php new file mode 100644 index 000000000..80ba2dfd8 --- /dev/null +++ b/tests/Mpdf/PageModeTest.php @@ -0,0 +1,94 @@ +render(function (Mpdf $mpdf) { + $mpdf->WriteHTML('
Hello
'); + }); + + $this->assertStringNotContainsString('/PageMode', $output); + } + + public function testBookmarksOpenTheOutlinePane() + { + $output = $this->render(function (Mpdf $mpdf) { + $mpdf->WriteHTML('Hello
'); + $mpdf->Bookmark('Chapter one'); + }); + + $this->assertSame(1, substr_count($output, '/PageMode')); + $this->assertStringContainsString('/PageMode /UseOutlines', $output); + } + + public function testUseAttachmentsDisplayPreference() + { + $output = $this->render(function (Mpdf $mpdf) { + $mpdf->SetDisplayPreferences('UseAttachments'); + $mpdf->WriteHTML('Hello
'); + }); + + $this->assertSame(1, substr_count($output, '/PageMode')); + $this->assertStringContainsString('/PageMode /UseAttachments', $output); + } + + /** + * A dictionary cannot hold the same key twice, so an explicit request has to beat the + * outline pane that bookmarks would otherwise ask for. + */ + public function testExplicitPreferenceWinsOverBookmarks() + { + $output = $this->render(function (Mpdf $mpdf) { + $mpdf->SetDisplayPreferences('UseAttachments'); + $mpdf->WriteHTML('Hello
'); + $mpdf->Bookmark('Chapter one'); + }); + + $this->assertSame(1, substr_count($output, '/PageMode')); + $this->assertStringContainsString('/PageMode /UseAttachments', $output); + } + + public function testFullScreenWinsOverUseAttachments() + { + $output = $this->render(function (Mpdf $mpdf) { + $mpdf->SetDisplayPreferences('FullScreenUseAttachments'); + $mpdf->WriteHTML('Hello
'); + }); + + $this->assertSame(1, substr_count($output, '/PageMode')); + $this->assertStringContainsString('/PageMode /FullScreen', $output); + } + + public function testLayerPaneWinsOverEverythingElse() + { + $output = $this->render(function (Mpdf $mpdf) { + $mpdf->open_layer_pane = true; + $mpdf->SetDisplayPreferences('FullScreen'); + $mpdf->SetVisibility('screenonly'); + $mpdf->WriteHTML('Hello
'); + $mpdf->SetVisibility('visible'); + $mpdf->Bookmark('Chapter one'); + }); + + $this->assertSame(1, substr_count($output, '/PageMode')); + $this->assertStringContainsString('/PageMode /UseOC', $output); + } + + private function render(callable $write) + { + $mpdf = new Mpdf(); + $mpdf->compress = false; + + $write($mpdf); + + $output = $mpdf->OutputBinaryData(); + $mpdf->cleanup(); + + return $output; + } + +}