include/vcl/gdimtf.hxx | 1 sw/source/core/view/vprint.cxx | 65 ++------ sw/source/uibase/docvw/AnnotationWin2.cxx | 13 + vcl/inc/pdf/pdfwriter_impl.hxx | 3 vcl/qa/cppunit/pdfexport/data/tdf152231.fodt | 208 +++++++++++++++++++++++++++ vcl/qa/cppunit/pdfexport/pdfexport.cxx | 110 ++++++++++++++ vcl/source/gdi/gdimtf.cxx | 7 vcl/source/gdi/pdfwriter_impl.cxx | 13 - 8 files changed, 365 insertions(+), 55 deletions(-)
New commits: commit 3f504e684560be7038a68e0941fad9cbcfc58fc6 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri Jun 30 14:56:48 2023 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Tue Jul 4 15:20:16 2023 +0200 tdf#152231 vcl: PDF/UA export: content of comments in the margin ... is also Artifact. The problem is that ImpEditEngine::Paint() always produces tags, it can't easily check if it's inside a layout environment that is an Artifact. But it looks like PDFWriterImpl::beginStructureElement() already wants to handle and suppress a structure element inside a NonStruct, except that it calls endStructureElementMCSeq() before checkEmitStructure(), so no structure marked content sequence is produced, but the content is outside the Artifact marked content sequence, and possibly a second Artifact marked content sequence will be opened once the structure element is finished. (btw, it's allowed to nest marked content sequences in PDF, but nesting a structure element inside an Artifact appears dubious) Change-Id: Ib3eef9c611e28242854c712ce974fd8cfecd8ac2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153810 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 9eacbf7874320d44b79966cac8fa59c52a191715) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153902 diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx index bad2d387511c..a9438be8fc13 100644 --- a/vcl/inc/pdf/pdfwriter_impl.hxx +++ b/vcl/inc/pdf/pdfwriter_impl.hxx @@ -1062,7 +1062,8 @@ i12626 void endPage(); void beginStructureElementMCSeq(); - void endStructureElementMCSeq(); + enum class EndMode { Default, OnlyStruct }; + void endStructureElementMCSeq(EndMode = EndMode::Default); /** checks whether a non struct element lies in the ancestor hierarchy of the current structure element diff --git a/vcl/qa/cppunit/pdfexport/data/tdf152231.fodt b/vcl/qa/cppunit/pdfexport/data/tdf152231.fodt new file mode 100644 index 000000000000..26b5d329b2aa --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf152231.fodt @@ -0,0 +1,208 @@ +<?xml version='1.0' encoding='UTF-8'?> +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:c alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns: meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:meta><meta:initial-creator>Gabor Kelemen LO</meta:initial-creator><meta:creation-date>2022-11-22T00:38:49.808000000</meta:creation-date><dc:date>2022-11-22T01:02:17.524000000</dc:date><dc:creator>Gabor Kelemen LO</dc:creator><meta:editing-duration>PT23M25S</meta:editing-duration><meta:editing-cycles>11</meta:editing-cycles><meta:generator>LibreOfficeDev/24.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/3d1f9c90605623e5c7e7dd2d28f87aaa45fb9c86</meta:generator><dc:title>aaa</dc:title><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="12" meta:word-count="291" meta:character-count="1539" meta:non-whitespace-character-count="1250"/><meta:print-date>2023-06-30T17:07:42.601941685</meta:print-date><meta:printed-by>PDF files</meta:printed-by></office:meta> + <office:font-face-decls> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Lucida Sans1" svg:font-family="'Lucida Sans'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="NSimSun1" svg:font-family="NSimSun" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:writing-mode="lr-tb" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0cm" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="NSimSun1" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="NSimSun1" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <style:style style:name="Line_20_numbering" style:display-name="Line numbering" style:family="text"/> + <text:outline-style style:name="Outline"> + <text:outline-level-style text:level="1" loext:num-list-format="%1%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="2" loext:num-list-format="%2%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="3" loext:num-list-format="%3%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="4" loext:num-list-format="%4%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="5" loext:num-list-format="%5%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="6" loext:num-list-format="%6%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="7" loext:num-list-format="%7%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="8" loext:num-list-format="%8%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="9" loext:num-list-format="%9%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="10" loext:num-list-format="%10%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + </text:outline-style> + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:style-name="Line_20_numbering" text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/> + <loext:theme loext:name="Office Theme"> + <loext:theme-colors loext:name="LibreOffice"> + <loext:color loext:name="dark1" loext:color="#000000"/> + <loext:color loext:name="light1" loext:color="#ffffff"/> + <loext:color loext:name="dark2" loext:color="#000000"/> + <loext:color loext:name="light2" loext:color="#ffffff"/> + <loext:color loext:name="accent1" loext:color="#18a303"/> + <loext:color loext:name="accent2" loext:color="#0369a3"/> + <loext:color loext:name="accent3" loext:color="#a33e03"/> + <loext:color loext:name="accent4" loext:color="#8e03a3"/> + <loext:color loext:name="accent5" loext:color="#c99c00"/> + <loext:color loext:name="accent6" loext:color="#c9211e"/> + <loext:color loext:name="hyperlink" loext:color="#0000ee"/> + <loext:color loext:name="followed-hyperlink" loext:color="#551a8b"/> + </loext:theme-colors> + </loext:theme> + </office:styles> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> + <style:text-properties/> + </style:style> + <style:style style:name="P2" style:family="paragraph"> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" fo:line-height="100%" fo:text-align="start" fo:text-indent="0cm" style:text-autospace="ideograph-alpha" style:punctuation-wrap="simple" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties fo:hyphenate="false" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false"/> + </style:style> + <style:style style:name="T1" style:family="text"> + <style:text-properties/> + </style:style> + <style:style style:name="T2" style:family="text"> + <style:text-properties fo:font-variant="normal" fo:text-transform="none" style:use-window-font-color="true" loext:opacity="0%" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:text-position="0% 100%" style:font-name="Liberation Serif" fo:font-size="10pt" fo:letter-spacing="normal" fo:language="de" fo:country="DE" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:text-underline-mode="continuous" style:text-overline-mode="continuous" style:text-line-through-mode="continuous" style:letter-kerning="true" fo:background-color="transparent" style:font-name-asian="NSimSun1" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:text-scale="100%" style:font-relief="none" style:text-overline-style="none" style:text-overline-color="font-color"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:page-layout style:name="pm2"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:page-layout style:name="pm3" style:page-usage="left"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:page-layout style:name="pm4" style:page-usage="right"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:page-layout style:name="pm5"> + <style:page-layout-properties fo:page-width="22.901cm" fo:page-height="11.4cm" style:num-format="1" style:print-orientation="landscape" fo:margin-top="0cm" fo:margin-bottom="0cm" fo:margin-left="0cm" fo:margin-right="0cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:page-layout style:name="pm6"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="1cm" fo:margin-bottom="1cm" fo:margin-left="2cm" fo:margin-right="1cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:page-layout style:name="pm7"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:page-layout style:name="pm8"> + <style:page-layout-properties fo:page-width="29.7cm" fo:page-height="21.001cm" style:num-format="1" style:print-orientation="landscape" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:style style:name="dp1" style:family="drawing-page"> + <style:drawing-page-properties draw:background-size="full"/> + </style:style> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1" draw:style-name="dp1"/> + </office:master-styles> + <office:body> + <office:text> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="Standard">He heard quiet steps behind him. </text:p> + <text:p text:style-name="Standard">That didn't bode well. </text:p> + <text:p text:style-name="Standard">Who could be following him this late at night and in this deadbeat part of town?</text:p> + <text:p text:style-name="Standard"><text:span text:style-name="T1">A</text:span>nd at this particular moment, just after he pulled off the big time and was making off with the greenbacks. </text:p> + <text:p text:style-name="Standard">Was there another crook who'd had the same idea, and was now watching him and waiting for a chance to grab the fruit of his labor? </text:p> + <text:p text:style-name="Standard">Or did the steps behind him mean that one of many law officers in town was on to him and just waiting to pounce and snap those cuffs on his wrists? </text:p> + <text:p text:style-name="Standard"><office:annotation office:name="__Annotation__234_1396804301" loext:resolved="false"> + <dc:creator>Gabor Kelemen LO</dc:creator> + <dc:date>2022-11-22T00:56:44.315000000</dc:date> + <meta:creator-initials>GK</meta:creator-initials> + <text:p text:style-name="P2"><text:span text:style-name="T2">This is a comment</text:span></text:p> + </office:annotation>He nervously looked all around.<office:annotation-end office:name="__Annotation__234_1396804301"/> </text:p> + <text:p text:style-name="Standard">Suddenly he saw the alley. </text:p> + <text:p text:style-name="Standard">Like lightning he darted off to the left and disappeared between the two warehouses almost falling </text:p> + <text:p text:style-name="Standard">over the trash can lying in the middle of the sidewalk. </text:p> + <text:p text:style-name="Standard">He tried to nervously tap his way along in the inky </text:p> + <text:p text:style-name="P1">darkness and suddenly stiffened: it was a dead-end, he would have to go back the way he had come. The steps got louder and louder, he saw the black outline of a figure coming around the corner. Is this the end of the line? he thought pressing himself back against the wall trying to make himself invisible in the dark, was all that planning and energy wasted? He was dripping with sweat now, cold and wet, he could smell the fear coming off his clothes. Suddenly next to him, with a barely noticeable squeak, a door swung quietly to and fro in the night's breeze. Could this be the haven he'd prayed for? Slowly he slid toward the door, pressing himself more and more into the wall, into the dark, away from his enemy. Would this door save his hide?</text:p> + </office:text> + </office:body> +</office:document> \ No newline at end of file diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx index 54f08de0a0ed..34492890fe7f 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -3204,6 +3204,116 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf139736) CPPUNIT_ASSERT(nArtifacts >= 3); } +CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf152231) +{ + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + + // Enable PDF/UA + uno::Sequence<beans::PropertyValue> aFilterData( + comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) }, + { "ExportNotesInMargin", uno::Any(true) }, + { "SelectPdfVersion", uno::Any(sal_Int32(17)) } })); + aMediaDescriptor["FilterData"] <<= aFilterData; + saveAsPDF(u"tdf152231.fodt"); + + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + + vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + // Uncompress it. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + auto pStart = static_cast<const char*>(aUncompressed.GetData()); + const char* const pEnd = pStart + aUncompressed.GetSize(); + + enum + { + Default, + Artifact, + Tagged + } state + = Default; + + auto nLine(0); + auto nTagged(0); + auto nArtifacts(0); + while (true) + { + ++nLine; + auto const pLine = ::std::find(pStart, pEnd, '\n'); + if (pLine == pEnd) + { + break; + } + std::string_view const line(pStart, pLine - pStart); + pStart = pLine + 1; + if (!line.empty() && line[0] != '%') + { + ::std::cerr << nLine << ": " << line << "\n"; + if (line == "/Artifact BMC") + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); + state = Artifact; + ++nArtifacts; + } + else if (o3tl::starts_with(line, "/Standard<</MCID ")) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); + state = Tagged; + ++nTagged; + } + else if (line == "EMC") + { + CPPUNIT_ASSERT_MESSAGE("unexpected end", state != Default); + state = Default; + } + else if (nLine > 1) // first line is expected "0.1 w" + { + CPPUNIT_ASSERT_MESSAGE("unexpected content outside MCS", state != Default); + } + } + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("unclosed MCS", Default, state); + CPPUNIT_ASSERT(nTagged >= 12); // text in body + // 1 annotation + CPPUNIT_ASSERT(nArtifacts >= 1); + + auto nPara(0); + for (const auto& rDocElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "StructElem") + { + auto pS = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("S")); + if (pS && pS->GetValue() == "Standard") + { + ++nPara; + auto pKids = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject->Lookup("K")); + CPPUNIT_ASSERT(pKids); + // one problem was that that some StructElem were missing kids + CPPUNIT_ASSERT(!pKids->GetElements().empty()); + } + } + } + CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nPara)>(12), nPara); +} + CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf149140) { aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index a15bf4ba0dc9..c65e004ca605 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -10772,12 +10772,13 @@ void PDFWriterImpl::beginStructureElementMCSeq() } } -void PDFWriterImpl::endStructureElementMCSeq() +void PDFWriterImpl::endStructureElementMCSeq(EndMode const endMode) { - if( m_nCurrentStructElement > 0 && // StructTreeRoot - ( m_bEmitStructure || m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement ) && - m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // must have an opened MC sequence - ) + if (m_nCurrentStructElement > 0 // not StructTreeRoot + && (m_bEmitStructure + || (endMode != EndMode::OnlyStruct + && m_aStructure[m_nCurrentStructElement].m_eType == PDFWriter::NonStructElement)) + && m_aStructure[m_nCurrentStructElement].m_bOpenMCSeq) { writeBuffer( "EMC\n" ); m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = false; @@ -10813,7 +10814,7 @@ sal_Int32 PDFWriterImpl::beginStructureElement( PDFWriter::StructElement eType, return -1; // close eventual current MC sequence - endStructureElementMCSeq(); + endStructureElementMCSeq(EndMode::OnlyStruct); if( m_nCurrentStructElement == 0 && eType != PDFWriter::Document && eType != PDFWriter::NonStructElement ) commit 81d9ca3015757f617c8420b079dfe1d5e1961c32 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri Jun 30 14:54:18 2023 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Tue Jul 4 15:20:10 2023 +0200 tdf#152231 sw: PDF/UA export: tag comments in the margin as Artifact Comments aren't part of the document content. There is a separate option "Comments as PDF annotations" in the dialog that can be enabled even in addition to "Comments in margin" for getting something that's presumably accessible in PDF readers. This doesn't work completely yet, because EditEngine still produces tags. Change-Id: I66c020103a69f1d1fbbf317ae6b638158cd51868 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153809 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 20901a1a8633dc693cfd6354d0b660b81c242b70) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153901 diff --git a/sw/source/uibase/docvw/AnnotationWin2.cxx b/sw/source/uibase/docvw/AnnotationWin2.cxx index 06efbfdb581f..c683e69b4204 100644 --- a/sw/source/uibase/docvw/AnnotationWin2.cxx +++ b/sw/source/uibase/docvw/AnnotationWin2.cxx @@ -56,6 +56,7 @@ #include <vcl/decoview.hxx> #include <vcl/event.hxx> #include <vcl/gradient.hxx> +#include <vcl/pdfextoutdevdata.hxx> #include <vcl/svapp.hxx> #include <vcl/settings.hxx> #include <vcl/ptrstyle.hxx> @@ -160,6 +161,13 @@ void SwAnnotationWin::DrawForPage(OutputDevice* pDev, const Point& rPt) // of the SysObj can provide meaningful results UnclipVisibleSysObj(); + vcl::PDFExtOutDevData *const pPDFExtOutDevData( + dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData())); + if (pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportTaggedPDF()) + { + pPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::NonStructElement, OUString()); + } + pDev->Push(); pDev->SetFillColor(mColorDark); @@ -237,6 +245,11 @@ void SwAnnotationWin::DrawForPage(OutputDevice* pDev, const Point& rPt) } pDev->Pop(); + + if (pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportTaggedPDF()) + { + pPDFExtOutDevData->EndStructureElement(); + } } void SwAnnotationWin::SetPosSizePixelRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, commit db97096e0f386881b7fecd868ba16def34a976ae Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri Jun 30 14:44:21 2023 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Tue Jul 4 15:20:03 2023 +0200 tdf#152231 vcl,sw: PDF/UA export: fix comments in the margin If enabled, the comments mess up the structure elements, because the PageSyncData::mActions stores indexes into the GDIMetaFile::m_aList vector, and in PageSyncData::PlaySyncPageAct() the indexes don't match. This is because SwViewShell::PrintOrPDFExport() replaces the GDIMetaFile with a temporary one, then records the page content, then applies scaling to the temporary one and replays it, recording with the original one; somehow replaying a temporary GDIMetaFile with 270 actions to one that already has 4 actions results in 392 actions. It's not obvious how this can work with the temporary GDIMetaFile, so try to get rid of it; not sure if there any drawbacks to this but the GDIMetaFile is freshly created by the caller in any case. Change-Id: Ic297367ea307aa8eee8d609751d06abf417e9629 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153808 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit a225b4dbd46897903b217969da5f97f2660022c9) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153897 diff --git a/include/vcl/gdimtf.hxx b/include/vcl/gdimtf.hxx index d62cd899623b..63bde564dcfd 100644 --- a/include/vcl/gdimtf.hxx +++ b/include/vcl/gdimtf.hxx @@ -115,6 +115,7 @@ public: void Move( tools::Long nX, tools::Long nY ); // additional Move method getting specifics how to handle MapMode( MapUnit::MapPixel ) void Move( tools::Long nX, tools::Long nY, tools::Long nDPIX, tools::Long nDPIY ); + void ScaleActions(double fScaleX, double fScaleY); void Scale( double fScaleX, double fScaleY ); void Scale( const Fraction& rScaleX, const Fraction& rScaleY ); void Rotate( Degree10 nAngle10 ); diff --git a/sw/source/core/view/vprint.cxx b/sw/source/core/view/vprint.cxx index 0ad22ccf5357..3cd0c524007e 100644 --- a/sw/source/core/view/vprint.cxx +++ b/sw/source/core/view/vprint.cxx @@ -446,32 +446,12 @@ bool SwViewShell::PrintOrPDFExport( // output device is now provided by a call from outside the Writer) pOutDev->Push(); - // fdo#36815 for comments in margins print to a metafile - // and then scale that metafile down so that the comments - // will fit on the real page, and replay that scaled - // output to the real outputdevice - GDIMetaFile *pOrigRecorder(nullptr); - std::unique_ptr<GDIMetaFile> pMetaFile; SwPostItMode nPostItMode = rPrintData.GetPrintPostIts(); // tdf#91680 Reserve space in margin for comments only if there are comments const bool bHasPostItsToPrintInMargins = ( nPostItMode == SwPostItMode::InMargins ) && sw_GetPostIts( GetDoc()->getIDocumentFieldsAccess(), nullptr ); - - if ( bHasPostItsToPrintInMargins ) - { - //get and disable the existing recorder - pOrigRecorder = pOutDev->GetConnectMetaFile(); - pOutDev->SetConnectMetaFile(nullptr); - // turn off output to the device - pOutDev->EnableOutput(false); - // just record the rendering commands to the metafile - // instead - pMetaFile.reset(new GDIMetaFile); - pMetaFile->SetPrefSize(pOutDev->GetOutputSize()); - pMetaFile->SetPrefMapMode(pOutDev->GetMapMode()); - pMetaFile->Record(pOutDev); - } + ::std::optional<tools::Long> oOrigHeight; // Print/PDF export for (multi-)selection has already generated a // temporary document with the selected text. @@ -535,32 +515,7 @@ bool SwViewShell::PrintOrPDFExport( pPostItManager->CalcRects(); pPostItManager->LayoutPostIts(); pPostItManager->DrawNotesForPage(pOutDev, nPage-1); - - //Stop recording now - pMetaFile->Stop(); - pMetaFile->WindStart(); - //Enable output to the device again - pOutDev->EnableOutput(); - //Restore the original recorder - pOutDev->SetConnectMetaFile(pOrigRecorder); - - //Now scale the recorded page down so the notes - //will fit in the final page - double fScale = 0.75; - tools::Long nOrigHeight = pStPage->getFrameArea().Height(); - tools::Long nNewHeight = nOrigHeight*fScale; - tools::Long nShiftY = (nOrigHeight-nNewHeight)/2; - pMetaFile->Scale( fScale, fScale ); - pMetaFile->WindStart(); - //Move the scaled page down to center it - //the other variant of Move does not map pixels - //back to the logical units correctly - pMetaFile->Move(0, convertTwipToMm100(nShiftY), pOutDev->GetDPIX(), pOutDev->GetDPIY()); - pMetaFile->WindStart(); - - //play back the scaled page - pMetaFile->Play(*pOutDev); - pMetaFile.reset(); + oOrigHeight.emplace(pStPage->getFrameArea().Height()); } } @@ -570,6 +525,22 @@ bool SwViewShell::PrintOrPDFExport( // output device is now provided by a call from outside the Writer) pOutDev->Pop(); + // avoid a warning about unbalanced Push/Pop by doing this last: + if (oOrigHeight) + { + // fdo#36815 Now scale the recorded page down so the comments in + // margins will fit in the final page + double fScale = 0.75; + tools::Long nNewHeight = *oOrigHeight*fScale; + tools::Long nShiftY = (*oOrigHeight-nNewHeight)/2; + GDIMetaFile *const pMetaFile = pOutDev->GetConnectMetaFile(); + pMetaFile->ScaleActions(fScale, fScale); + //Move the scaled page down to center it + //the other variant of Move does not map pixels + //back to the logical units correctly + pMetaFile->Move(0, convertTwipToMm100(nShiftY), pOutDev->GetDPIX(), pOutDev->GetDPIY()); + } + return true; } diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx index e8bb8ba7e0bd..313d03811780 100644 --- a/vcl/source/gdi/gdimtf.cxx +++ b/vcl/source/gdi/gdimtf.cxx @@ -727,7 +727,7 @@ void GDIMetaFile::Move( tools::Long nX, tools::Long nY, tools::Long nDPIX, tools } } -void GDIMetaFile::Scale( double fScaleX, double fScaleY ) +void GDIMetaFile::ScaleActions(double const fScaleX, double const fScaleY) { for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() ) { @@ -743,6 +743,11 @@ void GDIMetaFile::Scale( double fScaleX, double fScaleY ) pModAct->Scale( fScaleX, fScaleY ); } +} + +void GDIMetaFile::Scale( double fScaleX, double fScaleY ) +{ + ScaleActions(fScaleX, fScaleY); m_aPrefSize.setWidth( FRound( m_aPrefSize.Width() * fScaleX ) ); m_aPrefSize.setHeight( FRound( m_aPrefSize.Height() * fScaleY ) );