From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- sw/qa/extras/globalfilter/data/BulletAsImage.odt | Bin 0 -> 9113 bytes sw/qa/extras/globalfilter/data/SvgImageTest.odt | Bin 0 -> 13608 bytes sw/qa/extras/globalfilter/data/char_background.odt | Bin 0 -> 9737 bytes .../globalfilter/data/char_background_editing.docx | Bin 0 -> 12672 bytes sw/qa/extras/globalfilter/data/char_highlight.docx | Bin 0 -> 13213 bytes .../globalfilter/data/checkbox_form_field.odt | Bin 0 -> 8258 bytes sw/qa/extras/globalfilter/data/date_form_field.odt | Bin 0 -> 8830 bytes .../data/date_form_field_char_formatting.odt | Bin 0 -> 8432 bytes .../data/document_with_linked_graphic.odt | Bin 0 -> 21466 bytes .../globalfilter/data/document_with_two_images.odt | Bin 0 -> 204546 bytes .../globalfilter/data/dropdown_form_field.odt | Bin 0 -> 8285 bytes .../globalfilter/data/fieldmark_QUOTE_nest.docx | Bin 0 -> 13179 bytes .../globalfilter/data/fieldmark_QUOTE_nest.fodt | 133 ++ .../globalfilter/data/fieldmark_QUOTE_nest.rtf | 249 +++ sw/qa/extras/globalfilter/data/graphic_shape.odt | Bin 0 -> 100009 bytes .../globalfilter/data/images_with_special_IDs.odt | Bin 0 -> 169464 bytes sw/qa/extras/globalfilter/data/linked_graphic.jpg | Bin 0 -> 35738 bytes .../data/multiple_identical_graphics.odt | Bin 0 -> 13826 bytes sw/qa/extras/globalfilter/data/skipimages.doc | Bin 0 -> 19968 bytes sw/qa/extras/globalfilter/data/skipimages.docx | Bin 0 -> 10925 bytes .../data/tdf138345_charstyle_highlight.odt | Bin 0 -> 13304 bytes sw/qa/extras/globalfilter/data/tdf143311-1.docx | Bin 0 -> 34371 bytes sw/qa/extras/globalfilter/data/text13e.odt | Bin 0 -> 9718 bytes sw/qa/extras/globalfilter/data/text_form_field.odt | Bin 0 -> 8376 bytes sw/qa/extras/globalfilter/globalfilter.cxx | 2267 ++++++++++++++++++++ 25 files changed, 2649 insertions(+) create mode 100644 sw/qa/extras/globalfilter/data/BulletAsImage.odt create mode 100644 sw/qa/extras/globalfilter/data/SvgImageTest.odt create mode 100644 sw/qa/extras/globalfilter/data/char_background.odt create mode 100644 sw/qa/extras/globalfilter/data/char_background_editing.docx create mode 100644 sw/qa/extras/globalfilter/data/char_highlight.docx create mode 100644 sw/qa/extras/globalfilter/data/checkbox_form_field.odt create mode 100644 sw/qa/extras/globalfilter/data/date_form_field.odt create mode 100644 sw/qa/extras/globalfilter/data/date_form_field_char_formatting.odt create mode 100644 sw/qa/extras/globalfilter/data/document_with_linked_graphic.odt create mode 100644 sw/qa/extras/globalfilter/data/document_with_two_images.odt create mode 100644 sw/qa/extras/globalfilter/data/dropdown_form_field.odt create mode 100644 sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.docx create mode 100644 sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt create mode 100644 sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.rtf create mode 100644 sw/qa/extras/globalfilter/data/graphic_shape.odt create mode 100644 sw/qa/extras/globalfilter/data/images_with_special_IDs.odt create mode 100644 sw/qa/extras/globalfilter/data/linked_graphic.jpg create mode 100644 sw/qa/extras/globalfilter/data/multiple_identical_graphics.odt create mode 100644 sw/qa/extras/globalfilter/data/skipimages.doc create mode 100644 sw/qa/extras/globalfilter/data/skipimages.docx create mode 100644 sw/qa/extras/globalfilter/data/tdf138345_charstyle_highlight.odt create mode 100644 sw/qa/extras/globalfilter/data/tdf143311-1.docx create mode 100644 sw/qa/extras/globalfilter/data/text13e.odt create mode 100644 sw/qa/extras/globalfilter/data/text_form_field.odt create mode 100644 sw/qa/extras/globalfilter/globalfilter.cxx (limited to 'sw/qa/extras/globalfilter') diff --git a/sw/qa/extras/globalfilter/data/BulletAsImage.odt b/sw/qa/extras/globalfilter/data/BulletAsImage.odt new file mode 100644 index 0000000000..27622aac4e Binary files /dev/null and b/sw/qa/extras/globalfilter/data/BulletAsImage.odt differ diff --git a/sw/qa/extras/globalfilter/data/SvgImageTest.odt b/sw/qa/extras/globalfilter/data/SvgImageTest.odt new file mode 100644 index 0000000000..3b37fe7998 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/SvgImageTest.odt differ diff --git a/sw/qa/extras/globalfilter/data/char_background.odt b/sw/qa/extras/globalfilter/data/char_background.odt new file mode 100644 index 0000000000..d2dcea0695 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/char_background.odt differ diff --git a/sw/qa/extras/globalfilter/data/char_background_editing.docx b/sw/qa/extras/globalfilter/data/char_background_editing.docx new file mode 100644 index 0000000000..5e92fe8bbd Binary files /dev/null and b/sw/qa/extras/globalfilter/data/char_background_editing.docx differ diff --git a/sw/qa/extras/globalfilter/data/char_highlight.docx b/sw/qa/extras/globalfilter/data/char_highlight.docx new file mode 100644 index 0000000000..e601bac111 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/char_highlight.docx differ diff --git a/sw/qa/extras/globalfilter/data/checkbox_form_field.odt b/sw/qa/extras/globalfilter/data/checkbox_form_field.odt new file mode 100644 index 0000000000..14c931ed37 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/checkbox_form_field.odt differ diff --git a/sw/qa/extras/globalfilter/data/date_form_field.odt b/sw/qa/extras/globalfilter/data/date_form_field.odt new file mode 100644 index 0000000000..2b786a4146 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/date_form_field.odt differ diff --git a/sw/qa/extras/globalfilter/data/date_form_field_char_formatting.odt b/sw/qa/extras/globalfilter/data/date_form_field_char_formatting.odt new file mode 100644 index 0000000000..eb77026205 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/date_form_field_char_formatting.odt differ diff --git a/sw/qa/extras/globalfilter/data/document_with_linked_graphic.odt b/sw/qa/extras/globalfilter/data/document_with_linked_graphic.odt new file mode 100644 index 0000000000..e7aeda6e2e Binary files /dev/null and b/sw/qa/extras/globalfilter/data/document_with_linked_graphic.odt differ diff --git a/sw/qa/extras/globalfilter/data/document_with_two_images.odt b/sw/qa/extras/globalfilter/data/document_with_two_images.odt new file mode 100644 index 0000000000..54d3d666de Binary files /dev/null and b/sw/qa/extras/globalfilter/data/document_with_two_images.odt differ diff --git a/sw/qa/extras/globalfilter/data/dropdown_form_field.odt b/sw/qa/extras/globalfilter/data/dropdown_form_field.odt new file mode 100644 index 0000000000..caaa66acda Binary files /dev/null and b/sw/qa/extras/globalfilter/data/dropdown_form_field.odt differ diff --git a/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.docx b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.docx new file mode 100644 index 0000000000..9fbec01e0a Binary files /dev/null and b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.docx differ diff --git a/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt new file mode 100644 index 0000000000..86b17a15bb --- /dev/null +++ b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt @@ -0,0 +1,133 @@ + + + Michael StahlMichael Stahl22019-01-24T14:48:002019-01-24T14:48:00P0DLibreOfficeDev/7.5.0.0.alpha0$Linux_X86_64 LibreOffice_project/be346d6cdc87b18dc861279187915de42722e97015.0000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + QUOTE "foo + QUOTE "foo + bar + baz" foo + bar + baz + bar + baz" foo + foo + bar + baz + bar + baz + + + + \ No newline at end of file diff --git a/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.rtf b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.rtf new file mode 100644 index 0000000000..04c8384fd6 --- /dev/null +++ b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.rtf @@ -0,0 +1,249 @@ +{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch37\stshfloch37\stshfhich37\stshfbi0\deflang1031\deflangfe1031\themelang1031\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};} +{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;} +{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};} +{\fhimajor\f31502\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0302020204030204}Calibri Light;}{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};} +{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};} +{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};} +{\f279\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\f280\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};} +{\f282\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\f283\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};} +{\f284\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\f285\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};} +{\f286\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\f287\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}{\f619\fbidi \froman\fcharset238\fprq2 Cambria Math CE;} +{\f620\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f622\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f623\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f626\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;} +{\f627\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);}{\f649\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f650\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f652\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;} +{\f653\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f654\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\f655\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\f656\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;} +{\f657\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};} +{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};} +{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};} +{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};} +{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};} +{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};} +{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};} +{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};} +{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;}{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;} +{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\fhimajor\f31533\fbidi \fswiss\fcharset177\fprq2 Calibri Light (Hebrew);}{\fhimajor\f31534\fbidi \fswiss\fcharset178\fprq2 Calibri Light (Arabic);} +{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};} +{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};} +{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};} +{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};} +{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};} +{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};} +{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};} +{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};} +{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};} +{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};} +{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};} +{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};} +{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;} +{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);} +{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);} +{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};} +{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};} +{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};} +{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}}{\colortbl;\red0\green0\blue0; +\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128; +\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\*\defchp \loch\af37\hich\af37\dbch\af37 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 } +\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 +\fs22\lang1031\langfe1033\loch\f37\hich\af37\dbch\af37\cgrid\langnp1031\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\* +\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv +\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1031\langfe1031\loch\f37\hich\af37\dbch\af37\cgrid\langnp1031\langfenp1031 \snext11 \ssemihidden \sunhideused +Normal Table;}}{\*\pgptbl {\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}}{\*\rsidtbl \rsid1061464\rsid1922412\rsid5796261\rsid12332008\rsid13762899\rsid16735927}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1 +\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author Michael Stahl}{\operator Michael Stahl}{\creatim\yr2019\mo1\dy24\hr15\min48}{\revtim\yr2019\mo1\dy24\hr15\min48}{\version2}{\edmins0}{\nofpages1}{\nofwords13}{\nofchars89}{\nofcharsws101}{\vern57447}} +{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw11906\paperh16838\margl1417\margr1417\margt1417\margb1134\gutter0\ltrsect +\deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0 +\showxmlerrors1\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1417\dgvorigin1417\dghshow1\dgvshow1 +\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct +\asianbrkrule\rsidroot1061464\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0 +{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2 +\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6 +\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang +{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 +\fs22\lang1031\langfe1033\loch\af37\hich\af37\dbch\af37\cgrid\langnp1031\langfenp1033 {\field{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1061464 \hich\af37\dbch\af37\loch\f37 \hich\af37\dbch\af37\loch\f37 QUOTE "foo +\par }\pard \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid13762899 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1061464 \hich\af37\dbch\af37\loch\f37 }{\field{\*\fldinst {\rtlch\fcs1 \af0 +\ltrch\fcs0 \insrsid13762899 \hich\af37\dbch\af37\loch\f37 \hich\af37\dbch\af37\loch\f37 QUOTE "foo +\par \hich\af37\dbch\af37\loch\f37 bar +\par \hich\af37\dbch\af37\loch\f37 baz"\hich\af37\dbch\af37\loch\f37 }}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid13762899 \hich\af37\dbch\af37\loch\f37 foo +\par \hich\af37\dbch\af37\loch\f37 bar +\par \hich\af37\dbch\af37\loch\f37 baz}}}\sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid13762899 +\par }\pard \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1061464 \hich\af37\dbch\af37\loch\f37 bar +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang6153\langfe1033\langnp6153\insrsid1061464\charrsid13762899 \hich\af37\dbch\af37\loch\f37 baz"\hich\af37\dbch\af37\loch\f37 }}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 +\lang6153\langfe1033\langnp6153\insrsid13762899\charrsid13762899 \hich\af37\dbch\af37\loch\f37 foo +\par }\pard \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid13762899 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang6153\langfe1033\langnp6153\insrsid13762899\charrsid13762899 +\hich\af37\dbch\af37\loch\f37 }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang6153\langfe1033\langnp6153\insrsid13762899\charrsid13762899 \hich\af37\dbch\af37\loch\f37 foo +\par \hich\af37\dbch\af37\loch\f37 bar +\par \hich\af37\dbch\af37\loch\f37 baz +\par }\pard \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang6153\langfe1033\langnp6153\insrsid13762899\charrsid13762899 \hich\af37\dbch\af37\loch\f37 bar + +\par \hich\af37\dbch\af37\loch\f37 baz}}}\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 +\fs22\lang1031\langfe1033\loch\af37\hich\af37\dbch\af37\cgrid\langnp1031\langfenp1033 \sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af0 \ltrch\fcs0 +\lang6153\langfe1033\langnp6153\insrsid5796261\charrsid13762899 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang6153\langfe1033\langnp6153\insrsid16735927\charrsid1061464 +\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a +9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad +5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 +b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 +0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 +a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f +c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 +0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 +a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 +6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b +4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b +4757e8d3f729e245eb2b260a0238fd010000ffff0300504b030414000600080000002100aa5225dfc60600008b1a0000160000007468656d652f7468656d652f +7468656d65312e786d6cec595d8bdb46147d2ff43f08bd3bfe92fcb1c41b6cd9ceb6d94d42eca4e4716c8fadc98e344633de8d0981923c160aa569e943037deb +43691b48a02fe9afd936a54d217fa17746b63c638fbb9b2585a5640d8b343af7ce997bafce1d4997afdc8fa87384134e58dc708b970aae83e3211b9178d2706f +f7bbb99aeb7081e211a22cc60d778eb97b65f7c30f2ea31d11e2083b601ff31dd4704321a63bf93c1fc230e297d814c7706dcc920809384d26f951828ec16f44 +f3a542a1928f10895d274611b8bd311e932176fad2a5bbbb74dea1701a0b2e078634e949d7d8b050d8d1615122f89c0734718e106db830cf881df7f17de13a14 +7101171a6e41fdb9f9ddcb79b4b330a2628bad66d7557f0bbb85c1e8b0a4e64c26836c52cff3bd4a33f3af00546ce23ad54ea553c9fc29001a0e61a52917dda7 +dfaab7dafe02ab81d2438bef76b55d2e1a78cd7f798373d3973f03af40a97f6f03dfed06104503af4029dedfc07b5eb51478065e81527c65035f2d34db5ed5c0 +2b5048497cb8812ef89572b05c6d061933ba6785d77daf5b2d2d9caf50500d5975c929c62c16db6a2d42f758d2058004522448ec88f9148fd110aa3840940c12 +e2ec93490885374531e3305c2815ba8532fc973f4f1da988a01d8c346bc90b98f08d21c9c7e1c3844c45c3fd18bcba1ae4cdcb1fdfbc7cee9c3c7a71f2e89793 +c78f4f1efd9c3a32acf6503cd1ad5e7fffc5df4f3f75fe7afeddeb275fd9f15cc7fffed367bffdfaa51d082b5d85e0d5d7cffe78f1ecd5379ffff9c3130bbc99 +a0810eef930873e73a3e766eb10816a6426032c783e4ed2cfa2122ba45339e701423398bc57f478406fafa1c5164c1b5b019c13b09488c0d787576cf20dc0b93 +9920168fd7c2c8001e30465b2cb146e19a9c4b0b737f164fec9327331d770ba123dbdc018a8dfc766653d05662731984d8a07993a258a0098eb170e4357688b1 +6575770931e27a408609e36c2c9cbbc46921620d499f0c8c6a5a19ed9108f232b711847c1bb139b8e3b418b5adba8d8f4c24dc15885ac8f73135c27815cd048a +6c2efb28a27ac0f791086d247bf364a8e33a5c40a6279832a733c29cdb6c6e24b05e2de9d7405eec693fa0f3c84426821cda7cee23c674649b1d06218aa6366c +8fc4a18efd881f428922e7261336f80133ef10790e7940f1d674df21d848f7e96a701b9455a7b42a107965965872791533a37e7b733a4658490d08bfa1e71189 +4f15f73559f7ff5b5907217df5ed53cbaa2eaaa0371362bda3f6d6647c1b6e5dbc03968cc8c5d7ee369ac53731dc2e9b0decbd74bf976ef77f2fdddbeee7772f +d82b8d06f9965bc574abae36eed1d67dfb9850da13738af7b9daba73e84ca32e0c4a3bf5cc8ab3e7b8690887f24e86090cdc2441cac64998f88488b017a229ec +ef8bae7432e10bd713ee4c19876dbf1ab6fa96783a8b0ed8287d5c2d16e5a3692a1e1c89d578c1cfc6e15143a4e84a75f50896b9576c27ea51794940dabe0d09 +6d329344d942a2ba1c9441520fe610340b09b5b277c2a26e615193ee97a9da6001d4b2acc0d6c9810d57c3f53d30012378a242148f649ed2542fb3ab92f92e33 +bd2d984605c03e625901ab4cd725d7adcb93ab4b4bed0c99364868e566925091513d8c87688417d52947cf42e36d735d5fa5d4a02743a1e683d25ad1a8d6fe8d +c579730d76ebda40635d2968ec1c37dc4ad9879219a269c31dc3633f1c4653a81d2eb7bc884ee0ddd95024e90d7f1e6599265cb4110fd3802bd149d520220227 +0e2551c395cbcfd24063a5218a5bb104827061c9d541562e1a3948ba99643c1ee3a1d0d3ae8dc848a7a7a0f0a95658af2af3f383a5259b41ba7be1e8d819d059 +720b4189f9d5a20ce0887078fb534ca33922f03a3313b255fdad35a685eceaef13550da5e3884e43b4e828ba98a77025e5191d7596c5403b5bac1902aa8564d1 +080713d960f5a01add34eb1a2987ad5df7742319394d34573dd35015d935ed2a66ccb06c036bb13c5f93d7582d430c9aa677f854bad725b7bed4bab57d42d625 +20e059fc2c5df70c0d41a3b69acca026196fcab0d4ecc5a8d93b960b3c85da599a84a6fa95a5dbb5b8653dc23a1d0c9eabf383dd7ad5c2d078b9af549156df3d +f44f136c700fc4a30d2f81675470954af8f09020d810f5d49e24950db845ee8bc5ad0147ce2c210df741c16f7a41c90f72859adfc97965af90abf9cd72aee9fb +e562c72f16daadd243682c228c8a7efacda50bafa2e87cf1e5458d6f7c7d89966fdb2e0d599467eaeb4a5e11575f5f8aa5ed5f5f1c02a2f3a052ead6cbf55625 +572f37bb39afddaae5ea41a5956b57826abbdb0efc5abdfbd0758e14d86b9603afd2a9e52ac520c8799582a45fabe7aa5ea9d4f4aacd5ac76b3e5c6c6360e5a9 +7c2c6201e155bc76ff010000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f7468656d652f5f72656c732f +7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f2451eced0dae2c082e8761be +9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198720e274a939cd08a54f980 +ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528a2c6cce0239baa4c04ca5b +babac4df000000ffff0300504b01022d0014000600080000002100e9de0fbfff0000001c0200001300000000000000000000000000000000005b436f6e74656e +745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b00000000000000000000000000300100005f72656c732f +2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000190200007468656d652f7468656d652f74 +68656d654d616e616765722e786d6c504b01022d0014000600080000002100aa5225dfc60600008b1a00001600000000000000000000000000d6020000746865 +6d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b0100002700000000000000000000000000d00900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000cb0a00000000} +{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d +617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 +6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 +656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} +{\*\latentstyles\lsdstimax371\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature;\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong; +\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Table;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 1; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 6; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 6; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Contemporary;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Elegant;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Professional; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Theme;\lsdsemihidden1 \lsdlocked0 Placeholder Text; +\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2; +\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List; +\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;\lsdpriority61 \lsdlocked0 Light List Accent 1; +\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdsemihidden1 \lsdlocked0 Revision; +\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1; +\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;\lsdpriority72 \lsdlocked0 Colorful List Accent 1; +\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2; +\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2; +\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2; +\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3; +\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3; +\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4; +\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4; +\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4; +\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5; +\lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; +\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6; +\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6; +\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; +\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4; +\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2; +\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4; +\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4; +\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6; +\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3; +\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4; +\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4; +\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;}}{\*\datastore 010500000200000018000000 +4d73786d6c322e534158584d4c5265616465722e362e30000000000000000000000e0000 +d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffdffffff04000000feffffff05000000fefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff010000000c6ad98892f1d411a65f0040963251e500000000000000000000000010aa +78dbf3b3d4010300000080020000000000004d0073006f004400610074006100530074006f0072006500000000000000000000000000000000000000000000000000000000000000000000000000000000001a000101ffffffffffffffff02000000000000000000000000000000000000000000000010aa78dbf3b3d401 +10aa78dbf3b3d4010000000000000000000000004f00c600520049004f005800c7005400c700c40053003200d400c00033004b004100d800cc003000430041003d003d000000000000000000000000000000000032000101ffffffffffffffff03000000000000000000000000000000000000000000000010aa78dbf3b3 +d40110aa78dbf3b3d4010000000000000000000000004900740065006d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffff04000000ffffffff000000000000000000000000000000000000000000000000 +00000000000000000000000000000000f100000000000000010000000200000003000000feffffff0500000006000000070000000800000009000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c623a536f757263657320786d6c6e733a623d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f6772617068792220786d6c6e733d +22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222053656c65637465645374796c653d225c415041536978746845646974696f6e4f66666963654f6e6c696e652e78736c22205374796c654e616d +653d22415041222056657273696f6e3d2236222f3e0000000000000000000000000000003c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d226e6f223f3e0d0a3c64733a6461746173746f72654974656d2064733a6974656d49443d227b33393438 +363433412d443337392d343439452d394344322d3037344130333842314130387d2220786d6c6e733a64733d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f637573746f6d586d6c223e3c64733a736368656d61526566733e3c +64733a736368656d615265662064733a7572693d22687474703a2f2f736368656d61732e6f70656e500072006f007000650072007400690065007300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000200ffffffffffffffffffffffff000000000000 +0000000000000000000000000000000000000000000000000000000000000400000055010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222f3e3c2f64733a736368656d61526566733e3c2f64733a6461746173746f +72654974656d3e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105000000000000}} \ No newline at end of file diff --git a/sw/qa/extras/globalfilter/data/graphic_shape.odt b/sw/qa/extras/globalfilter/data/graphic_shape.odt new file mode 100644 index 0000000000..425e8c2f32 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/graphic_shape.odt differ diff --git a/sw/qa/extras/globalfilter/data/images_with_special_IDs.odt b/sw/qa/extras/globalfilter/data/images_with_special_IDs.odt new file mode 100644 index 0000000000..d4c62f5d2b Binary files /dev/null and b/sw/qa/extras/globalfilter/data/images_with_special_IDs.odt differ diff --git a/sw/qa/extras/globalfilter/data/linked_graphic.jpg b/sw/qa/extras/globalfilter/data/linked_graphic.jpg new file mode 100644 index 0000000000..2218cdd72d Binary files /dev/null and b/sw/qa/extras/globalfilter/data/linked_graphic.jpg differ diff --git a/sw/qa/extras/globalfilter/data/multiple_identical_graphics.odt b/sw/qa/extras/globalfilter/data/multiple_identical_graphics.odt new file mode 100644 index 0000000000..20f40798ed Binary files /dev/null and b/sw/qa/extras/globalfilter/data/multiple_identical_graphics.odt differ diff --git a/sw/qa/extras/globalfilter/data/skipimages.doc b/sw/qa/extras/globalfilter/data/skipimages.doc new file mode 100644 index 0000000000..3c40599b08 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/skipimages.doc differ diff --git a/sw/qa/extras/globalfilter/data/skipimages.docx b/sw/qa/extras/globalfilter/data/skipimages.docx new file mode 100644 index 0000000000..cc6a4f4cea Binary files /dev/null and b/sw/qa/extras/globalfilter/data/skipimages.docx differ diff --git a/sw/qa/extras/globalfilter/data/tdf138345_charstyle_highlight.odt b/sw/qa/extras/globalfilter/data/tdf138345_charstyle_highlight.odt new file mode 100644 index 0000000000..6886ed8f71 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/tdf138345_charstyle_highlight.odt differ diff --git a/sw/qa/extras/globalfilter/data/tdf143311-1.docx b/sw/qa/extras/globalfilter/data/tdf143311-1.docx new file mode 100644 index 0000000000..b6b2d08981 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/tdf143311-1.docx differ diff --git a/sw/qa/extras/globalfilter/data/text13e.odt b/sw/qa/extras/globalfilter/data/text13e.odt new file mode 100644 index 0000000000..bb16e0467e Binary files /dev/null and b/sw/qa/extras/globalfilter/data/text13e.odt differ diff --git a/sw/qa/extras/globalfilter/data/text_form_field.odt b/sw/qa/extras/globalfilter/data/text_form_field.odt new file mode 100644 index 0000000000..96af26f770 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/text_form_field.odt differ diff --git a/sw/qa/extras/globalfilter/globalfilter.cxx b/sw/qa/extras/globalfilter/globalfilter.cxx new file mode 100644 index 0000000000..9d7c28b83f --- /dev/null +++ b/sw/qa/extras/globalfilter/globalfilter.cxx @@ -0,0 +1,2267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Test : public SwModelTestBase +{ +public: + Test() : SwModelTestBase("/sw/qa/extras/globalfilter/data/") {} + + void testEmbeddedGraphicRoundtrip(); + void testLinkedGraphicRT(); + void testImageWithSpecialID(); + void testGraphicShape(); + void testMultipleIdenticalGraphics(); + void testCharHighlight(); + void testCharHighlightODF(); + void testCharHighlightBody(); + void testCharStyleHighlight(); + void testMSCharBackgroundEditing(); + void testCharBackgroundToHighlighting(); +#if !defined(_WIN32) + void testSkipImages(); +#endif + void testNestedFieldmark(); + void verifyText13(char const*); + void testODF13(); + void testRedlineFlags(); + void testBulletAsImage(); + void testTextFormField(); + void testCheckBoxFormField(); + void testDropDownFormField(); + void testDateFormField(); + void testDateFormFieldCharacterFormatting(); + void testSvgImageSupport(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testEmbeddedGraphicRoundtrip); + CPPUNIT_TEST(testLinkedGraphicRT); + CPPUNIT_TEST(testImageWithSpecialID); + CPPUNIT_TEST(testGraphicShape); + CPPUNIT_TEST(testMultipleIdenticalGraphics); + CPPUNIT_TEST(testCharHighlight); + CPPUNIT_TEST(testCharHighlightODF); + CPPUNIT_TEST(testMSCharBackgroundEditing); + CPPUNIT_TEST(testCharBackgroundToHighlighting); +#if !defined(_WIN32) + CPPUNIT_TEST(testSkipImages); +#endif + CPPUNIT_TEST(testNestedFieldmark); + CPPUNIT_TEST(testODF13); + CPPUNIT_TEST(testRedlineFlags); + CPPUNIT_TEST(testBulletAsImage); + CPPUNIT_TEST(testTextFormField); + CPPUNIT_TEST(testCheckBoxFormField); + CPPUNIT_TEST(testDropDownFormField); + CPPUNIT_TEST(testDateFormField); + CPPUNIT_TEST(testDateFormFieldCharacterFormatting); + CPPUNIT_TEST(testSvgImageSupport); + CPPUNIT_TEST_SUITE_END(); +}; + +void Test::testEmbeddedGraphicRoundtrip() +{ + OUString aFilterNames[] = { + "writer8", + "Rich Text Format", + "MS Word 97", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + // Check whether the export code swaps in the image which was swapped out before by auto mechanism + + createSwDoc("document_with_two_images.odt"); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check whether graphic exported well after it was swapped out + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 2, getShapes()); + + // First image + uno::Reference xImage(getShape(1), uno::UNO_QUERY); + uno::Reference< beans::XPropertySet > XPropSet( xImage, uno::UNO_QUERY_THROW ); + + // Check graphic, size + { + uno::Reference xGraphic; + XPropSet->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), graphic::GraphicType::PIXEL, xGraphic->getType()); + uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(610), xBitmap->getSize().Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(381), xBitmap->getSize().Height); + } + + // Second Image + xImage.set(getShape(2), uno::UNO_QUERY); + XPropSet.set( xImage, uno::UNO_QUERY_THROW ); + + // Check graphic, size + { + uno::Reference xGraphic; + XPropSet->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), graphic::GraphicType::PIXEL, xGraphic->getType()); + uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(900), xBitmap->getSize().Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(600), xBitmap->getSize().Height); + } + } +} + +void Test::testLinkedGraphicRT() +{ + const OUString aFilterNames[] = { + "writer8", +// "Rich Text Format", Note: picture is there, but SwGrfNode is not found? + "MS Word 97", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + createSwDoc("document_with_linked_graphic.odt"); + + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pDoc); + SwNodes& aNodes = pDoc->GetNodes(); + + // Find the image + bool bImageFound = false; + Graphic aGraphic; + for (SwNodeOffset nIndex(0); nIndex < aNodes.Count(); ++nIndex) + { + if (aNodes[nIndex]->IsGrfNode()) + { + SwGrfNode* pGrfNode = aNodes[nIndex]->GetGrfNode(); + CPPUNIT_ASSERT(pGrfNode); + + const GraphicObject& rGraphicObj = pGrfNode->GetGrfObj(true); + aGraphic = rGraphicObj.GetGraphic(); + bImageFound = true; + } + } + + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), bImageFound); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_uLong(864900), aGraphic.GetSizeBytes()); + + // Check if linked graphic is registered in LinkManager + sfx2::LinkManager& rLinkManager = pTextDoc->GetDocShell()->GetDoc()->GetEditShell()->GetLinkManager(); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), size_t(1), rLinkManager.GetLinks().size()); + const tools::SvRef & rLink = rLinkManager.GetLinks()[0]; + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), rLink->GetLinkSourceName().indexOf("linked_graphic.jpg") >= 0); + } +} + +void Test::testImageWithSpecialID() +{ + // Check how LO handles when the imported graphic's ID is different from that one + // which is generated by LO. + + const OUString aFilterNames[] = { + "writer8", + "Rich Text Format", + "MS Word 97", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + createSwDoc("images_with_special_IDs.odt"); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check whether graphic exported well + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 2, getShapes()); + + uno::Reference xImage = getShape(1); + uno::Reference< beans::XPropertySet > XPropSet( xImage, uno::UNO_QUERY_THROW ); + + // Check graphic, size + { + uno::Reference xGraphic; + XPropSet->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), graphic::GraphicType::PIXEL, xGraphic->getType()); + uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(610), xBitmap->getSize().Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(381), xBitmap->getSize().Height); + } + + // Second Image + xImage.set(getShape(2), uno::UNO_QUERY); + XPropSet.set( xImage, uno::UNO_QUERY_THROW ); + + // Check graphic, size + { + uno::Reference xGraphic; + XPropSet->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), graphic::GraphicType::PIXEL, xGraphic->getType()); + uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(900), xBitmap->getSize().Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(600), xBitmap->getSize().Height); + } + } +} + +/// Gives the first embedded or linked image in a document. +static uno::Reference lcl_getShape(const uno::Reference& xComponent, bool bEmbedded) +{ + uno::Reference xShape; + + uno::Reference xDrawPageSupplier(xComponent, uno::UNO_QUERY); + uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); + for (sal_Int32 i = 0; i < xDrawPage->getCount(); ++i) + { + uno::Reference xShapeProperties(xDrawPage->getByIndex(i), uno::UNO_QUERY); + uno::Reference xGraphic; + xShapeProperties->getPropertyValue("Graphic") >>= xGraphic; + if (xGraphic.is()) + { + Graphic aGraphic(xGraphic); + + if (bEmbedded == aGraphic.getOriginURL().isEmpty()) + { + xShape.set(xShapeProperties, uno::UNO_QUERY); + return xShape; + } + } + } + + return xShape; +} + +void Test::testGraphicShape() +{ + // There are two kind of images in Writer: 1) Writer specific handled by SwGrfNode and + // 2) graphic shape handled by SdrGrafObj (e.g. after copy&paste from Impress). + + const OUString aFilterNames[] = { + "writer8", + "Rich Text Format", + "MS Word 97", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + createSwDoc("graphic_shape.odt"); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check whether graphic exported well + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 2, getShapes()); + + uno::Reference xImage = lcl_getShape(mxComponent, true); + CPPUNIT_ASSERT_MESSAGE("Couldn't load the shape/image", xImage.is()); + uno::Reference< beans::XPropertySet > XPropSet( xImage, uno::UNO_QUERY ); + // First image is embedded + // Check size + { + uno::Reference xGraphic; + XPropSet->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); + uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(610), xBitmap->getSize().Width ); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(381), xBitmap->getSize().Height ); + } + + // MS filters make this kind of linked images broken !? + if (rFilterName != "writer8") + return; + + // Second image is a linked one + xImage = lcl_getShape(mxComponent, false); + XPropSet.set(xImage, uno::UNO_QUERY); + const OString sFailedImageLoad = OString::Concat("Couldn't load the shape/image for ") + rFilterName.toUtf8(); + CPPUNIT_ASSERT_MESSAGE(sFailedImageLoad.getStr(), xImage.is()); + + // Check size + { + uno::Reference xGraphic; + XPropSet->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); + + Graphic aGraphic(xGraphic); + OUString sURL = aGraphic.getOriginURL(); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), sURL.endsWith("linked_graphic.jpg")); + + uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(620), xBitmap->getSize().Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(465), xBitmap->getSize().Height); + } + } +} + +namespace +{ + +std::vector> + lcl_getGraphics(const uno::Reference& xComponent) +{ + std::vector> aGraphics; + + uno::Reference xDrawPageSupplier(xComponent, uno::UNO_QUERY); + uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); + for (sal_Int32 i = 0; i < xDrawPage->getCount(); ++i) + { + uno::Reference xShapeProperties(xDrawPage->getByIndex(i), uno::UNO_QUERY); + uno::Reference xGraphic; + xShapeProperties->getPropertyValue("Graphic") >>= xGraphic; + if (xGraphic.is()) + { + aGraphics.push_back(xGraphic); + } + } + + return aGraphics; +} + +} + +void Test::testMultipleIdenticalGraphics() +{ + // We have multiple identical graphics. When we save them we want + // them to be saved de-duplicated and the same should still be true + // after loading them again. This test check that the de-duplication + // works as expected. + + const OUString aFilterNames[] { + "writer8", + //"Rich Text Format", // doesn't work correctly for now + "MS Word 97", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + createSwDoc("multiple_identical_graphics.odt"); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check whether graphic exported well + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + auto aGraphics = lcl_getGraphics(mxComponent); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), size_t(5), aGraphics.size()); + + // Get all GfxLink addresses, we expect all of them to be the same + // indicating we use the same graphic instance for all shapes + std::vector aGfxLinkAddresses; + for (auto const & rxGraphic : aGraphics) + { + GfxLink* pLink = Graphic(rxGraphic).GetSharedGfxLink().get(); + aGfxLinkAddresses.emplace_back(reinterpret_cast(pLink)); + } + + // Check all addresses are the same + bool bResult = std::equal(aGfxLinkAddresses.begin() + 1, aGfxLinkAddresses.end(), aGfxLinkAddresses.begin()); + const OString sGraphicNotTheSameFailedMessage = OString::Concat("Graphics not the same for filter: '") + + rFilterName.toUtf8() + OString::Concat("'"); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sGraphicNotTheSameFailedMessage.getStr(), true, bResult); + } +} + +void Test::testCharHighlightBody() +{ + // MS Word has two kind of character backgrounds called character shading and highlighting + // MS filters handle these attributes separately, but ODF export merges them into one background attribute + + const OUString aFilterNames[] = { + "writer8", + "Rich Text Format", + "MS Word 97", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + createSwDoc("char_highlight.docx"); + + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + const uno::Reference< text::XTextRange > xPara = getParagraph(1); + // Both highlight and background + const Color nBackColor(0x4F81BD); + for( int nRun = 1; nRun <= 16; ++nRun ) + { + const uno::Reference xRun(getRun(xPara,nRun), uno::UNO_QUERY); + Color nHighlightColor; + switch( nRun ) + { + case 1: nHighlightColor = COL_BLACK; break; //black 0x000000 + case 2: nHighlightColor = COL_LIGHTBLUE; break; //light blue 0x0000ff + case 3: nHighlightColor = COL_LIGHTCYAN; break; //light cyan 0x00ffff + case 4: nHighlightColor = COL_LIGHTGREEN; break; //light green 0x00ff00 + case 5: nHighlightColor = COL_LIGHTMAGENTA; break; //light magenta 0xff00ff + case 6: nHighlightColor = COL_LIGHTRED; break; //light red 0xff0000 + case 7: nHighlightColor = COL_YELLOW; break; //yellow 0xffff00 + case 8: nHighlightColor = COL_WHITE; break; //white 0xffffff + case 9: nHighlightColor = COL_BLUE; break;//blue 0x000080 + case 10: nHighlightColor = COL_CYAN; break; //cyan 0x008080 + case 11: nHighlightColor = COL_GREEN; break; //green 0x008000 + case 12: nHighlightColor = COL_MAGENTA; break; //magenta 0x800080 + case 13: nHighlightColor = COL_RED; break; //red 0x800000 + case 14: nHighlightColor = COL_BROWN; break; //brown 0x808000 + case 15: nHighlightColor = COL_GRAY; break; //dark gray 0x808080 + case 16: nHighlightColor = COL_LIGHTGRAY; break; //light gray 0xC0C0C0 + } + + if (rFilterName == "writer8") + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), nHighlightColor, getProperty(xRun,"CharBackColor")); + } + else // MS filters + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), nHighlightColor, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), nBackColor, getProperty(xRun,"CharBackColor")); + } + } + + // Only highlight + { + const uno::Reference xRun(getRun(xPara,18), uno::UNO_QUERY); + if (rFilterName == "writer8") + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_LIGHTRED, getProperty(xRun,"CharBackColor")); + } + else + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_LIGHTRED, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharBackColor")); + } + } + + // Only background + { + const uno::Reference xRun(getRun(xPara,19), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_LIGHTBLUE, getProperty(xRun,"CharBackColor")); + } + } +} + +void Test::testCharStyleHighlight() +{ + // MS Word has two kind of character backgrounds called character shading and highlighting. + // However, their character style can only accept shading. It ignores the highlighting value. + + const OUString aFilterNames[] = { + "Rich Text Format", + "MS Word 97", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + createSwDoc("tdf138345_charstyle_highlight.odt"); + + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + uno::Reference xCharStyle; + getStyles("CharacterStyles")->getByName("charBackground") >>= xCharStyle; + const Color nBackColor(0xFFDBB6); //orange-y + + // Always export character style's background colour as shading, never as highlighting. + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xCharStyle,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), nBackColor, getProperty(xCharStyle,"CharBackColor")); + } +} + +void Test::testCharHighlight() +{ + SvtFilterOptions& rOpt = SvtFilterOptions::Get(); + rOpt.SetCharBackground2Shading(); + + testCharHighlightBody(); + testCharStyleHighlight(); + + rOpt.SetCharBackground2Highlighting(); + + testCharHighlightBody(); + testCharStyleHighlight(); +} + +void Test::testCharHighlightODF() +{ + createSwDoc("char_background_editing.docx"); + + // don't check import, testMSCharBackgroundEditing already does that + + uno::Reference xPara = getParagraph(1); + for (int i = 1; i <= 4; ++i) + { + uno::Reference xRun(getRun(xPara,i), uno::UNO_QUERY); + switch (i) + { + case 1: // non-transparent highlight + xRun->setPropertyValue("CharBackColor", uno::Any(static_cast(128))); + xRun->setPropertyValue("CharBackTransparent", uno::Any(true)); + xRun->setPropertyValue("CharHighlight", uno::Any(static_cast(64))); + break; + + case 2: // transparent backcolor + xRun->setPropertyValue("CharBackColor", uno::Any(static_cast(128))); + xRun->setPropertyValue("CharBackTransparent", uno::Any(true)); + xRun->setPropertyValue("CharHighlight", uno::Any(static_cast(COL_TRANSPARENT))); + break; + + case 3: // non-transparent backcolor + xRun->setPropertyValue("CharBackColor", uno::Any(static_cast(128))); + xRun->setPropertyValue("CharBackTransparent", uno::Any(false)); + xRun->setPropertyValue("CharHighlight", uno::Any(static_cast(COL_TRANSPARENT))); + break; + + case 4: // non-transparent highlight again + xRun->setPropertyValue("CharBackColor", uno::Any(static_cast(128))); + xRun->setPropertyValue("CharBackTransparent", uno::Any(false)); + xRun->setPropertyValue("CharHighlight", uno::Any(static_cast(64))); + break; + } + } + + saveAndReload("writer8"); + + xPara.set(getParagraph(1)); + for (int i = 1; i <= 4; ++i) + { + uno::Reference xRun(getRun(xPara,i), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(static_cast(COL_TRANSPARENT), getProperty(xRun, "CharHighlight")); + switch (i) + { + case 1: // non-transparent highlight + CPPUNIT_ASSERT_EQUAL(Color(0x000040), getProperty(xRun, "CharBackColor")); + CPPUNIT_ASSERT_EQUAL(false, getProperty(xRun, "CharBackTransparent")); + break; + case 2: // transparent backcolor + CPPUNIT_ASSERT_EQUAL(COL_TRANSPARENT, getProperty(xRun, "CharBackColor")); + CPPUNIT_ASSERT_EQUAL(true, getProperty(xRun, "CharBackTransparent")); + break; + case 3: // non-transparent backcolor + CPPUNIT_ASSERT_EQUAL(COL_BLUE, getProperty(xRun, "CharBackColor")); + CPPUNIT_ASSERT_EQUAL(false, getProperty(xRun, "CharBackTransparent")); + break; + case 4: // non-transparent highlight again + CPPUNIT_ASSERT_EQUAL(Color(0x000040), getProperty(xRun, "CharBackColor")); + CPPUNIT_ASSERT_EQUAL(false, getProperty(xRun, "CharBackTransparent")); + break; + } + } +} + +void Test::testMSCharBackgroundEditing() +{ + // Simulate the editing process of imported MSO character background attributes + // and check how export behaves. + + const OUString aFilterNames[] = { + "writer8", + "Rich Text Format", + "MS Word 97", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + createSwDoc("char_background_editing.docx"); + + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + // Check whether import was done on the right way + uno::Reference< text::XTextRange > xPara = getParagraph(1); + { + uno::Reference xRun(getRun(xPara,1), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_LIGHTRED, getProperty(xRun,"CharBackColor")); + + xRun.set(getRun(xPara,2), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_LIGHTBLUE, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharBackColor")); + + xRun.set(getRun(xPara,3), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_LIGHTBLUE, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_LIGHTRED, getProperty(xRun,"CharBackColor")); + + xRun.set(getRun(xPara,4), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharBackColor")); + } + + // Simulate editing + for( int i = 1; i <= 4; ++i ) + { + uno::Reference xRun(getRun(xPara,i), uno::UNO_QUERY); + // Change background + Color nBackColor; + switch( i ) + { + case 1: nBackColor = COL_BLACK; break; //black 0x000000 + case 2: nBackColor = COL_LIGHTCYAN; break; //cyan 0x00ffff + case 3: nBackColor = COL_LIGHTGREEN; break; //green 0x00ff00 + case 4: nBackColor = COL_LIGHTMAGENTA; break; //magenta 0xff00ff + } + xRun->setPropertyValue("CharBackColor", uno::Any(nBackColor)); + // Remove highlighting + xRun->setPropertyValue("CharHighlight", uno::Any(COL_TRANSPARENT)); + // Remove shading marker + uno::Sequence aGrabBag = getProperty >(xRun,"CharInteropGrabBag"); + for (beans::PropertyValue& rProp : asNonConstRange(aGrabBag)) + { + if (rProp.Name == "CharShadingMarker") + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), true, rProp.Value.get()); + rProp.Value <<= false; + } + } + xRun->setPropertyValue("CharInteropGrabBag", uno::Any(aGrabBag)); + } + + SvtFilterOptions& rOpt = SvtFilterOptions::Get(); + rOpt.SetCharBackground2Highlighting(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check whether background was exported as highlighting + xPara.set(getParagraph(1)); + for( int i = 1; i <= 4; ++i ) + { + Color nBackColor; + switch( i ) + { + case 1: nBackColor = COL_BLACK; break; //black 0x000000 + case 2: nBackColor = COL_LIGHTCYAN; break; //light cyan 0x00ffff + case 3: nBackColor = COL_LIGHTGREEN; break; //light green 0x00ff00 + case 4: nBackColor = COL_LIGHTMAGENTA; break; //light magenta 0xff00ff + } + const uno::Reference xRun(getRun(xPara,i), uno::UNO_QUERY); + if (rFilterName == "writer8") + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), nBackColor, getProperty(xRun,"CharBackColor")); + } + else + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), nBackColor, getProperty(xRun,"CharHighlight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_TRANSPARENT, getProperty(xRun,"CharBackColor")); + } + } + } +} + +void Test::testCharBackgroundToHighlighting() +{ + // MSO highlighting has less kind of values so let's see how LO character background is converted + // to these values + + const OUString aFilterNames[] = { + "Rich Text Format", + "MS Word 97", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + createSwDoc("char_background.odt"); + + OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + + SvtFilterOptions& rOpt = SvtFilterOptions::Get(); + rOpt.SetCharBackground2Highlighting(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check highlight color + const uno::Reference< text::XTextRange > xPara = getParagraph(1); + for( int nRun = 1; nRun <= 19; ++nRun ) + { + const uno::Reference xRun(getRun(xPara,nRun), uno::UNO_QUERY); + Color nHighlightColor; + switch( nRun ) + { + case 1: nHighlightColor = COL_BLACK; break; //black 0x000000 + case 2: nHighlightColor = COL_YELLOW; break; //yellow 0xffff00 + case 3: nHighlightColor = COL_LIGHTMAGENTA; break; //light magenta 0xff00ff + case 4: nHighlightColor = COL_LIGHTCYAN; break; //light cyan 0x00ffff + case 5: nHighlightColor = COL_YELLOW; break; //yellow 0xffff00 + case 6: nHighlightColor = COL_LIGHTRED; break; //light red 0xff0000 + case 7: nHighlightColor = COL_LIGHTBLUE; break; //light blue 0x0000ff + case 8: nHighlightColor = COL_LIGHTGREEN; break; //light green 0x00ff00 + case 9: nHighlightColor = COL_GREEN; break; //dark green 0x008000 + case 10: nHighlightColor = COL_MAGENTA; break; //dark magenta 0x800080 + case 11: nHighlightColor = COL_BLUE; break; //dark blue 0x000080 + case 12: nHighlightColor = COL_BROWN; break; //brown 0x808000 + case 13: nHighlightColor = COL_GRAY; break; //dark gray 0x808080 + case 14: nHighlightColor = COL_BLACK; break; //black 0x000000 + case 15: nHighlightColor = COL_LIGHTRED; break; //light red 0xff0000 + case 16: nHighlightColor = COL_LIGHTGRAY; break; //light gray 0xC0C0C0 + case 17: nHighlightColor = COL_RED; break; //dark red 0x800000 + case 18: nHighlightColor = COL_GRAY; break; //dark gray 0x808080 + case 19: nHighlightColor = COL_YELLOW; break; //yellow 0xffff00 + } + const OString sMessage = sFailedMessage +". Index of run with unmatched color: " + OString::number(nRun); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage.getStr(), nHighlightColor, getProperty(xRun,"CharHighlight")); + } + } +} + +#if !defined(_WIN32) +void Test::testSkipImages() +{ + // Check how LO skips image loading (but not texts of textboxes and custom shapes) + // during DOC and DOCX import, using the "SkipImages" FilterOptions. + + std::pair aFilterNames[] = { + { "skipimages.doc", "" }, + { "skipimages.doc", "SkipImages" }, + { "skipimages.docx", "" }, + { "skipimages.docx", "SkipImages" } + }; + + for (auto const & rFilterNamePair : aFilterNames) + { + bool bSkipImages = !rFilterNamePair.second.isEmpty(); + OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterNamePair.first.toUtf8(); + + setImportFilterOptions(rFilterNamePair.second); + createSwDoc(rFilterNamePair.first.toUtf8().getStr()); + sFailedMessage += " - " + rFilterNamePair.second.toUtf8(); + + // Check shapes (images, textboxes, custom shapes) + uno::Reference xShape; + uno::Reference xGraphic; + uno::Reference< beans::XPropertySet > XPropSet; + uno::Reference xBitmap; + + bool bHasTextboxText = false; + bool bHasCustomShapeText = false; + sal_Int32 nImageCount = 0; + + for (int i = 1; i<= getShapes(); i++) + { + xShape = getShape(i); + XPropSet.set( xShape, uno::UNO_QUERY_THROW ); + try + { + XPropSet->getPropertyValue("Graphic") >>= xGraphic; + xBitmap.set(xGraphic, uno::UNO_QUERY); + if (xBitmap.is()) + nImageCount++; + } + catch (beans::UnknownPropertyException &) + { /* ignore */ } + + uno::Reference xText(xShape, uno::UNO_QUERY); + if (xText.is()) + { + OUString shapeText = xText->getString(); + if (shapeText.startsWith("Lorem ipsum")) + bHasTextboxText = true; + else if (shapeText.startsWith("Nam pretium")) + bHasCustomShapeText = true; + } + } + + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), bHasTextboxText); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), bHasCustomShapeText); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(bSkipImages ? 0 : 3), nImageCount ); + } +} +#endif + +static auto verifyNestedFieldmark(OUString const& rTestName, + uno::Reference const& xComponent) -> void +{ + SwDoc const*const pDoc(dynamic_cast(*xComponent).GetDocShell()->GetDoc()); + IDocumentMarkAccess const& rIDMA(*pDoc->getIDocumentMarkAccess()); + + // no spurious bookmarks have been created + CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName.toUtf8().getStr(), + sal_Int32(0), rIDMA.getBookmarksCount()); + + // check inner fieldmark + SwNodeIndex const node1(*pDoc->GetNodes().GetEndOfContent().StartOfSectionNode(), +2); + SwPosition const innerPos(*node1.GetNode().GetTextNode(), + node1.GetNode().GetTextNode()->GetText().indexOf(CH_TXT_ATR_FIELDSTART)); + CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName.toUtf8().getStr(), + sal_Int32(1), innerPos.GetContentIndex()); + ::sw::mark::IFieldmark *const pInner(rIDMA.getFieldmarkAt(innerPos)); + CPPUNIT_ASSERT_MESSAGE(rTestName.toUtf8().getStr(), pInner); + OUString const innerString(SwPaM(pInner->GetMarkPos(), pInner->GetOtherMarkPos()).GetText()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName.toUtf8().getStr(), OUString( + OUStringChar(CH_TXT_ATR_FIELDSTART) + u" QUOTE \"foo " + OUStringChar(CH_TXTATR_NEWLINE) + + u" bar " + OUStringChar(CH_TXTATR_NEWLINE) + + u"baz\" " + OUStringChar(CH_TXT_ATR_FIELDSEP) + u"foo " + OUStringChar(CH_TXTATR_NEWLINE) + + u" bar " + OUStringChar(CH_TXTATR_NEWLINE) + + u"baz" + OUStringChar(CH_TXT_ATR_FIELDEND)), innerString); + + // check outer fieldmark + SwNodeIndex const node2(node1, -1); + SwPosition const outerPos(*node2.GetNode().GetTextNode(), + node2.GetNode().GetTextNode()->GetText().indexOf(CH_TXT_ATR_FIELDSTART)); + CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName.toUtf8().getStr(), + sal_Int32(0), outerPos.GetContentIndex()); + ::sw::mark::IFieldmark const*const pOuter(rIDMA.getFieldmarkAt(outerPos)); + CPPUNIT_ASSERT_MESSAGE(rTestName.toUtf8().getStr(), pOuter); + OUString const outerString(SwPaM(pOuter->GetMarkPos(), pOuter->GetOtherMarkPos()).GetText()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName.toUtf8().getStr(), OUString( + OUStringChar(CH_TXT_ATR_FIELDSTART) + u" QUOTE \"foo " + OUStringChar(CH_TXTATR_NEWLINE) + + u" " + OUStringChar(CH_TXT_ATR_FIELDSTART) + u" QUOTE \"foo " + OUStringChar(CH_TXTATR_NEWLINE) + + u" bar " + OUStringChar(CH_TXTATR_NEWLINE) + + u"baz\" " + OUStringChar(CH_TXT_ATR_FIELDSEP) + u"foo " + OUStringChar(CH_TXTATR_NEWLINE) + + u" bar " + OUStringChar(CH_TXTATR_NEWLINE) + + u"baz" + OUStringChar(CH_TXT_ATR_FIELDEND) + OUStringChar(CH_TXTATR_NEWLINE) + + u"bar " + OUStringChar(CH_TXTATR_NEWLINE) + + u"baz\" " + OUStringChar(CH_TXT_ATR_FIELDSEP) + u"foo " + OUStringChar(CH_TXTATR_NEWLINE) + + u" foo " + OUStringChar(CH_TXTATR_NEWLINE) + + u" bar " + OUStringChar(CH_TXTATR_NEWLINE) + + u"baz" + OUStringChar(CH_TXTATR_NEWLINE) + + u"bar " + OUStringChar(CH_TXTATR_NEWLINE) + + u"baz" + OUStringChar(CH_TXT_ATR_FIELDEND)), outerString); + + // must return innermost mark + CPPUNIT_ASSERT_EQUAL(pInner, rIDMA.getInnerFieldmarkFor(innerPos)); +} + +void Test::testNestedFieldmark() +{ + // experimental config setting + Resetter resetter( + [] () { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Filter::Microsoft::Import::ForceImportWWFieldsAsGenericFields::set(false, pBatch); + return pBatch->commit(); + }); + std::shared_ptr pBatch(comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Filter::Microsoft::Import::ForceImportWWFieldsAsGenericFields::set(true, pBatch); + pBatch->commit(); + + std::pair const aFilterNames[] = { + {"writer8", "fieldmark_QUOTE_nest.fodt"}, + {"Office Open XML Text", "fieldmark_QUOTE_nest.docx"}, + {"Rich Text Format", "fieldmark_QUOTE_nest.rtf"}, + }; + + for (auto const & rFilterName : aFilterNames) + { + createSwDoc(rFilterName.second.toUtf8().getStr()); + + verifyNestedFieldmark(rFilterName.first + ", load", mxComponent); + + // Export the document and import again + saveAndReload(rFilterName.first); + + verifyNestedFieldmark(rFilterName.first + " exported-reload", mxComponent); + } +} + +auto Test::verifyText13(char const*const pTestName) -> void +{ + // OFFICE-3789 style:header-first/style:footer-first + uno::Reference xPageStyle; + getStyles("PageStyles")->getByName("Standard") >>= xPageStyle; + uno::Reference xHF(getProperty>(xPageStyle, "HeaderTextFirst")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, OUString("Header first"), xHF->getString()); + uno::Reference xFF(getProperty>(xPageStyle, "FooterTextFirst")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, OUString("Footer first"), xFF->getString()); + // OFFICE-3767 text:contextual-spacing + uno::Reference xPara(getParagraph(1)); + CPPUNIT_ASSERT_MESSAGE(pTestName, getProperty(xPara, "ParaContextMargin")); + // OFFICE-3776 meta:creator-initials + uno::Reference xRun(getRun(xPara, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, OUString("Annotation"), getProperty(xRun, "TextPortionType")); + uno::Reference xComment(getProperty>(xRun, "TextField")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, OUString("dj"), getProperty(xComment, "Initials")); + // OFFICE-3941 text:index-entry-link-start/text:index-entry-link-end + uno::Reference xDIS(mxComponent, uno::UNO_QUERY); + uno::Reference xIndexes(xDIS->getDocumentIndexes()); + uno::Reference xIndex(xIndexes->getByIndex(0), uno::UNO_QUERY); + uno::Reference xLevels(getProperty>(xIndex, "LevelFormat")); + uno::Sequence format; + xLevels->getByIndex(1) >>= format; // 1-based? + CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, OUString("TokenType"), format[0][0].Name); + CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, OUString("TokenHyperlinkStart"), format[0][0].Value.get()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, OUString("TokenType"), format[4][0].Name); + CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, OUString("TokenHyperlinkEnd"), format[4][0].Value.get()); +} + +// test ODF 1.3 new text document features +void Test::testODF13() +{ + // import + createSwDoc("text13e.odt"); + + // check model + verifyText13("import"); + + Resetter _([]() { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + return pBatch->commit(); + }); + + { + // export ODF 1.3 + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch); + pBatch->commit(); + + saveAndReload("writer8"); + + // check XML + xmlDocUniquePtr pContentXml = parseExport("content.xml"); + assertXPath(pContentXml, "/office:document-content/office:automatic-styles/style:style/style:paragraph-properties[@style:contextual-spacing='true']"_ostr); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:p/office:annotation/meta:creator-initials"_ostr); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:p/office:annotation/loext:sender-initials"_ostr, 0); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-start"_ostr); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-start"_ostr, 0); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-end"_ostr); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-end"_ostr, 0); + xmlDocUniquePtr pStylesXml = parseExport("styles.xml"); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/style:header-first"_ostr); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/loext:header-first"_ostr, 0); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/style:footer-first"_ostr); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/loext:footer-first"_ostr, 0); + + // check model + verifyText13("1.3 reload"); + } + { + // export ODF 1.2 extended + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(9, pBatch); + pBatch->commit(); + + // FIXME: it's not possible to use 'reload' here because the validation fails with + // Error: unexpected attribute "loext:contextual-spacing" + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer8"); + + uno::Reference const xStorable(mxComponent, uno::UNO_QUERY); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // check XML + xmlDocUniquePtr pContentXml = parseExport("content.xml"); + assertXPath(pContentXml, "/office:document-content/office:automatic-styles/style:style/style:paragraph-properties[@loext:contextual-spacing='true']"_ostr); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:p/office:annotation/loext:sender-initials"_ostr); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:p/office:annotation/meta:creator-initials"_ostr, 0); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-start"_ostr); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-start"_ostr, 0); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-end"_ostr); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-end"_ostr, 0); + xmlDocUniquePtr pStylesXml = parseExport("styles.xml"); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/loext:header-first"_ostr); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/style:header-first"_ostr, 0); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/loext:footer-first"_ostr); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/style:footer-first"_ostr, 0); + + // reload + mxComponent->dispose(); + mxComponent = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument"); + + // check model + verifyText13("1.2 Extended reload"); + } + { + // export ODF 1.2 + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(4, pBatch); + pBatch->commit(); + + // don't reload - no point + save("writer8"); + + // check XML + xmlDocUniquePtr pContentXml = parseExport("content.xml"); + assertXPathNoAttribute(pContentXml, "/office:document-content/office:automatic-styles/style:style/style:paragraph-properties"_ostr, "contextual-spacing"_ostr); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:p/office:annotation/meta:creator-initials"_ostr, 0); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:p/office:annotation/loext:sender-initials"_ostr, 0); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-start"_ostr, 0); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-start"_ostr, 0); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-end"_ostr, 0); + assertXPath(pContentXml, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-end"_ostr, 0); + xmlDocUniquePtr pStylesXml = parseExport("styles.xml"); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/style:header-first"_ostr, 0); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/loext:header-first"_ostr, 0); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/style:footer-first"_ostr, 0); + assertXPath(pStylesXml, "/office:document-styles/office:master-styles/style:master-page/loext:footer-first"_ostr, 0); + } +} + +void Test::testRedlineFlags() +{ + const OUString aFilterNames[] = { + "writer8", + "Rich Text Format", + "MS Word 97", + "Office Open XML Text", + }; + + createSwDoc(); + SwDoc* pDoc = getSwDoc(); + + SwPaM pam(SwPosition(pDoc->GetNodes().GetEndOfContent(), SwNodeOffset(-1))); + pDoc->getIDocumentContentOperations().InsertString(pam, "foo bar baz"); + + IDocumentRedlineAccess & rIDRA(pDoc->getIDocumentRedlineAccess()); + // enable change tracking + rIDRA.SetRedlineFlags(rIDRA.GetRedlineFlags() + | RedlineFlags::On | RedlineFlags::ShowDelete); + + // need a delete redline to trigger mode switching + pam.Move(fnMoveForward, GoInDoc); + pam.SetMark(); + pam.Move(fnMoveBackward, GoInDoc); + pDoc->getIDocumentContentOperations().DeleteAndJoin(pam); + + // hide delete redlines + RedlineFlags const nRedlineFlags = + rIDRA.GetRedlineFlags() & ~RedlineFlags::ShowDelete; + rIDRA.SetRedlineFlags(nRedlineFlags); + + for (OUString const & rFilterName : aFilterNames) + { + // export the document + save(rFilterName); + + // tdf#97103 check that redline mode is properly restored + CPPUNIT_ASSERT_EQUAL_MESSAGE( + OString(OString::Concat("redline mode not restored in ") + rFilterName.toUtf8()).getStr(), + static_cast(nRedlineFlags), static_cast(rIDRA.GetRedlineFlags())); + } +} + +void Test::testBulletAsImage() +{ + OUString aFilterNames[] = { + "writer8", + "MS Word 97", + "Office Open XML Text", + "Rich Text Format", + }; + + for (OUString const & rFilterName : aFilterNames) + { + OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + createSwDoc("BulletAsImage.odt"); + + // Check if import was successful + { + uno::Reference xPara(getParagraph(1)); + uno::Reference xPropertySet(xPara, uno::UNO_QUERY); + uno::Reference xLevels; + xLevels.set(xPropertySet->getPropertyValue("NumberingRules"), uno::UNO_QUERY); + uno::Sequence aProperties; + xLevels->getByIndex(0) >>= aProperties; + uno::Reference xBitmap; + awt::Size aSize; + sal_Int16 nNumberingType = -1; + + for (beans::PropertyValue const & rProperty : std::as_const(aProperties)) + { + if (rProperty.Name == "NumberingType") + { + nNumberingType = rProperty.Value.get(); + } + else if (rProperty.Name == "GraphicBitmap") + { + if (rProperty.Value.has>()) + { + xBitmap = rProperty.Value.get>(); + } + } + else if (rProperty.Name == "GraphicSize") + { + aSize = rProperty.Value.get(); + } + } + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), style::NumberingType::BITMAP, nNumberingType); + + // Graphic Bitmap + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); + Graphic aGraphic(uno::Reference(xBitmap, uno::UNO_QUERY)); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), aGraphic.GetSizeBytes() > o3tl::make_unsigned(0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), tools::Long(16), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), tools::Long(16), aGraphic.GetSizePixel().Height()); + + // Graphic Size + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(400), aSize.Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(400), aSize.Height); + } + + // Export the document and import again for a check + saveAndReload(rFilterName); + + { + uno::Reference xPara(getParagraph(1)); + uno::Reference xPropertySet(xPara, uno::UNO_QUERY); + uno::Reference xLevels; + xLevels.set(xPropertySet->getPropertyValue("NumberingRules"), uno::UNO_QUERY); + uno::Sequence aProperties; + xLevels->getByIndex(0) >>= aProperties; + uno::Reference xBitmap; + awt::Size aSize; + sal_Int16 nNumberingType = -1; + + for (beans::PropertyValue const & rProperty : std::as_const(aProperties)) + { + if (rProperty.Name == "NumberingType") + { + nNumberingType = rProperty.Value.get(); + } + else if (rProperty.Name == "GraphicBitmap") + { + if (rProperty.Value.has>()) + { + xBitmap = rProperty.Value.get>(); + } + } + else if (rProperty.Name == "GraphicSize") + { + aSize = rProperty.Value.get(); + } + } + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), style::NumberingType::BITMAP, nNumberingType); + + // Graphic Bitmap + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); + Graphic aGraphic(uno::Reference(xBitmap, uno::UNO_QUERY)); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), aGraphic.GetSizeBytes() > o3tl::make_unsigned(0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), tools::Long(16), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), tools::Long(16), aGraphic.GetSizePixel().Height()); + + // Graphic Size + if (rFilterName == "write8") // ODT is correct + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(400), aSize.Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(400), aSize.Height); + } + // FIXME: MS Filters don't work correctly for graphic bullet size + else if (rFilterName == "Office Open XML Text" || rFilterName == "Rich Text Format") + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(279), aSize.Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(279), aSize.Height); + } + else if (rFilterName == "MS Word 97") + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(296), aSize.Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(296), aSize.Height); + } + } + } +} + +CPPUNIT_TEST_FIXTURE(Test, testListLabelPDFExport) +{ + createSwDoc(); + + uno::Reference xDoc(mxComponent, uno::UNO_QUERY_THROW); + uno::Reference xText(xDoc->getText()); + uno::Reference xFactory(mxComponent, uno::UNO_QUERY_THROW); + uno::Reference xNumRule( + xFactory->createInstance("com.sun.star.text.NumberingRules"), + uno::UNO_QUERY_THROW); + OUString listFormat; + for (sal_Int32 i = 0; i < xNumRule->getCount(); ++i) + { + uno::Sequence format; + format.getArray(); + xNumRule->getByIndex(i) >>= format; + { + auto it(::std::find_if(format.begin(), format.end(), + [](auto const& r) { return r.Name == "NumberingType"; })); + // need something RTL + const_cast(it->Value) <<= style::NumberingType::CHARS_ARABIC; + } + { +#if 0 + // this doesn't work any more + auto it(::std::find_if(format.begin(), format.end(), + [](auto const& r) { return r.Name == "ParentNumbering"; })); + const_cast(it->Value) <<= sal_Int16(i + 1); +#endif + listFormat += "%" + OUString::number(i+1) + "%."; + auto it(::std::find_if(format.begin(), format.end(), + [](auto const& r) { return r.Name == "ListFormat"; })); + const_cast(it->Value) <<= listFormat; + } + xNumRule->replaceByIndex(i, uno::Any(format)); + } + uno::Reference(getParagraph(1), uno::UNO_QUERY_THROW)->setPropertyValue("NumberingRules", uno::Any(xNumRule)); + xText->insertControlCharacter(xText->getEnd(), text::ControlCharacter::PARAGRAPH_BREAK, false); + uno::Reference(getParagraph(2), uno::UNO_QUERY_THROW)->setPropertyValue("NumberingLevel", uno::Any(sal_Int16(1))); + xText->insertControlCharacter(xText->getEnd(), text::ControlCharacter::PARAGRAPH_BREAK, false); + uno::Reference(getParagraph(3), uno::UNO_QUERY_THROW)->setPropertyValue("NumberingLevel", uno::Any(sal_Int16(2))); + + // check PDF export of the list items (label in particular) + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + // Enable PDF/UA + uno::Sequence aFilterData( + comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } })); + aMediaDescriptor["FilterData"] <<= aFilterData; + css::uno::Reference xStorable(mxComponent, css::uno::UNO_QUERY_THROW); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + std::unique_ptr pPdfDocument = parsePDFExport(); + + // Non-NULL pPdfDocument means pdfium is available. + if (pPdfDocument != nullptr) + { + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); + std::unique_ptr pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); + CPPUNIT_ASSERT(pPdfPage); + + std::unique_ptr pPdfTextPage = pPdfPage->getTextPage(); + CPPUNIT_ASSERT(pPdfTextPage); + + int nChars = pPdfTextPage->countChars(); + CPPUNIT_ASSERT_EQUAL(22, nChars); + + // Check that the label strings were exported correctly + std::vector aChars(nChars); + for (int i = 0; i < nChars; i++) + aChars[i] = pPdfTextPage->getUnicode(i); + OUString aText(aChars.data(), aChars.size()); + CPPUNIT_ASSERT_EQUAL(u"\u0623\r\n.\r\n\u0623.\u0623\r\n.\r\n\u0623.\u0623.\u0623\r\n."_ustr, aText); + } + + // Parse the document again to get its raw content + // TODO: get the content from PDFiumPage somehow + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // The document has one page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + + vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"_ostr); + 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(aUncompressed.GetData()); + const char* const pEnd = pStart + aUncompressed.GetSize(); + + enum + { + Default, + Lbl, + LblFoundText + } state + = Default; + + auto nLine(0); + auto nLbl(0); + auto nLblTj(0); + auto nLblTJ(0); + std::vector mcids; + 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 (o3tl::starts_with(line, "/Lbl<>BDC")) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); + mcids.push_back(o3tl::toInt32(line.substr(12))); + state = Lbl; + ++nLbl; + } + else if (state == Lbl) + { + auto const endj(line.find(">Tj")); + if (endj != ::std::string_view::npos) + { + state = LblFoundText; + ++nLblTj; + } + else + { + auto const endJ(line.find("]TJ")); + if (endJ != ::std::string_view::npos) + { + state = LblFoundText; + ++nLblTJ; + } + } + } + else if (state != Default && line == "EMC") + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("missing text", LblFoundText, state); + state = Default; + } + } + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("unclosed MCS", Default, state); + // ideally there should be 3 but apparently every text portion gets its own + // tag - this should not be a problem if these are grouped in the structure + // tree into 3 Lbl. + CPPUNIT_ASSERT_EQUAL(static_cast(6), nLbl); + // these are quite arbitrary? + CPPUNIT_ASSERT_EQUAL(static_cast(6), nLblTJ + nLblTj); + + auto nL(0); + for (const auto& rDocElement : aDocument.GetElements()) + { + auto pObject0 = dynamic_cast(rDocElement.get()); + if (!pObject0) + continue; + auto pType0 = dynamic_cast(pObject0->Lookup("Type"_ostr)); + if (!pType0 || pType0->GetValue() != "StructElem") + { + continue; + } + auto pS0 = dynamic_cast(pObject0->Lookup("S"_ostr)); + if (!pS0 || pS0->GetValue() != "Document") + { + continue; + } + auto pKids0 = dynamic_cast(pObject0->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids0); + + for (const auto& pKid0 : pKids0->GetElements()) + { + auto pRefKid0 = dynamic_cast(pKid0); + CPPUNIT_ASSERT(pRefKid0); + auto pObject1 = pRefKid0->LookupObject(); + CPPUNIT_ASSERT(pObject1); + auto pType1 = dynamic_cast(pObject1->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType1); + + if (pType1 && pType1->GetValue() == "StructElem") + { + auto pS1 = dynamic_cast(pObject1->Lookup("S"_ostr)); + if (pS1 && pS1->GetValue() == "L") + { + ++nL; + auto pKids1 = dynamic_cast(pObject1->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids1); + // this is purely structural so there should be 1 child + CPPUNIT_ASSERT_EQUAL(size_t(1), pKids1->GetElements().size()); + + auto pRefKid11 = dynamic_cast(pKids1->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid11); + auto pObject11 = pRefKid11->LookupObject(); + CPPUNIT_ASSERT(pObject11); + auto pType11 = dynamic_cast(pObject11->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType11); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType11->GetValue()); + auto pS11 = dynamic_cast(pObject11->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS11); + CPPUNIT_ASSERT_EQUAL("LI"_ostr, pS11->GetValue()); + // LI has 2 children: Lbl and LBody + auto pKids11 = dynamic_cast(pObject11->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids11); + CPPUNIT_ASSERT_EQUAL(size_t(2), pKids11->GetElements().size()); + + auto pRefKid111 = dynamic_cast(pKids11->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid111); + auto pObject111 = pRefKid111->LookupObject(); + CPPUNIT_ASSERT(pObject111); + auto pType111 = dynamic_cast(pObject111->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType111); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType111->GetValue()); + auto pS111 = dynamic_cast(pObject111->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS111); + CPPUNIT_ASSERT_EQUAL("Lbl"_ostr, pS111->GetValue()); + // Lbl has 2 children: the first 2 mcids (in order) + auto pKids111 = dynamic_cast(pObject111->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids111); + CPPUNIT_ASSERT_EQUAL(size_t(2), pKids111->GetElements().size()); + + auto pRefKid1111 = dynamic_cast(pKids111->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid1111); + CPPUNIT_ASSERT_EQUAL(mcids[0], int(pRefKid1111->GetValue())); + auto pRefKid1112 = dynamic_cast(pKids111->GetElements()[1]); + CPPUNIT_ASSERT(pRefKid1112); + CPPUNIT_ASSERT_EQUAL(mcids[1], int(pRefKid1112->GetValue())); + + auto pRefKid112 = dynamic_cast(pKids11->GetElements()[1]); + CPPUNIT_ASSERT(pRefKid112); + auto pObject112 = pRefKid112->LookupObject(); + CPPUNIT_ASSERT(pObject112); + auto pType112 = dynamic_cast(pObject112->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType112); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType112->GetValue()); + auto pS112 = dynamic_cast(pObject112->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS112); + CPPUNIT_ASSERT_EQUAL("LBody"_ostr, pS112->GetValue()); + // LBody has 2 children: paragraph and nested L (in order) + auto pKids112 = dynamic_cast(pObject112->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids112); + CPPUNIT_ASSERT_EQUAL(size_t(2), pKids112->GetElements().size()); + + auto pRefKid1121 = dynamic_cast(pKids112->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid1121); + auto pObject1121 = pRefKid1121->LookupObject(); + CPPUNIT_ASSERT(pObject1121); + auto pType1121 = dynamic_cast(pObject1121->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType1121); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType1121->GetValue()); + auto pS1121 = dynamic_cast(pObject1121->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS1121); + CPPUNIT_ASSERT_EQUAL("Standard"_ostr, pS1121->GetValue()); + + auto pRefKid1122 = dynamic_cast(pKids112->GetElements()[1]); + CPPUNIT_ASSERT(pRefKid1122); + auto pObject1122 = pRefKid1122->LookupObject(); + CPPUNIT_ASSERT(pObject1122); + auto pType1122 = dynamic_cast(pObject1122->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType1122); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType1122->GetValue()); + auto pS1122 = dynamic_cast(pObject1122->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS1122); + CPPUNIT_ASSERT_EQUAL("L"_ostr, pS1122->GetValue()); + auto pKids1122 = dynamic_cast(pObject1122->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids1122); + // this is purely structural so there should be 1 child + CPPUNIT_ASSERT_EQUAL(size_t(1), pKids1122->GetElements().size()); + + auto pRefKid11221 = dynamic_cast(pKids1122->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid11221); + auto pObject11221 = pRefKid11221->LookupObject(); + CPPUNIT_ASSERT(pObject11221); + auto pType11221 = dynamic_cast(pObject11221->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType11221); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType11221->GetValue()); + auto pS11221 = dynamic_cast(pObject11221->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS11221); + CPPUNIT_ASSERT_EQUAL("LI"_ostr, pS11221->GetValue()); + // LI has 2 children: Lbl and LBody + auto pKids11221 = dynamic_cast(pObject11221->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids11221); + CPPUNIT_ASSERT_EQUAL(size_t(2), pKids11221->GetElements().size()); + + auto pRefKid112211 = dynamic_cast(pKids11221->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid112211); + auto pObject112211 = pRefKid112211->LookupObject(); + CPPUNIT_ASSERT(pObject112211); + auto pType112211 = dynamic_cast(pObject112211->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType112211); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType112211->GetValue()); + auto pS112211 = dynamic_cast(pObject112211->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS112211); + CPPUNIT_ASSERT_EQUAL("Lbl"_ostr, pS112211->GetValue()); + // Lbl has 2 children: the first 2 mcids (in order) + auto pKids112211 = dynamic_cast(pObject112211->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids112211); + CPPUNIT_ASSERT_EQUAL(size_t(2), pKids112211->GetElements().size()); + + auto pRefKid1122111 = dynamic_cast(pKids112211->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid1122111); + CPPUNIT_ASSERT_EQUAL(mcids[2], int(pRefKid1122111->GetValue())); + auto pRefKid1122112 = dynamic_cast(pKids112211->GetElements()[1]); + CPPUNIT_ASSERT(pRefKid1122112); + CPPUNIT_ASSERT_EQUAL(mcids[3], int(pRefKid1122112->GetValue())); + + auto pRefKid112212 = dynamic_cast(pKids11221->GetElements()[1]); + CPPUNIT_ASSERT(pRefKid112212); + auto pObject112212 = pRefKid112212->LookupObject(); + CPPUNIT_ASSERT(pObject112212); + auto pType112212 = dynamic_cast(pObject112212->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType112212); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType112212->GetValue()); + auto pS112212 = dynamic_cast(pObject112212->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS112212); + CPPUNIT_ASSERT_EQUAL("LBody"_ostr, pS112212->GetValue()); + // LBody has 2 children: paragraph and nested L (in order) + auto pKids112212 = dynamic_cast(pObject112212->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids112212); + CPPUNIT_ASSERT_EQUAL(size_t(2), pKids112212->GetElements().size()); + + auto pRefKid1122121 = dynamic_cast(pKids112212->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid1122121); + auto pObject1122121 = pRefKid1122121->LookupObject(); + CPPUNIT_ASSERT(pObject1122121); + auto pType1122121 = dynamic_cast(pObject1122121->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType1122121); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType1122121->GetValue()); + auto pS1122121 = dynamic_cast(pObject1122121->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS1122121); + CPPUNIT_ASSERT_EQUAL("Standard"_ostr, pS1122121->GetValue()); + + auto pRefKid1122122 = dynamic_cast(pKids112212->GetElements()[1]); + CPPUNIT_ASSERT(pRefKid1122122); + auto pObject1122122 = pRefKid1122122->LookupObject(); + CPPUNIT_ASSERT(pObject1122122); + auto pType1122122 = dynamic_cast(pObject1122122->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType1122122); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType1122122->GetValue()); + auto pS1122122 = dynamic_cast(pObject1122122->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS1122122); + CPPUNIT_ASSERT_EQUAL("L"_ostr, pS1122122->GetValue()); + auto pKids1122122 = dynamic_cast(pObject1122122->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids1122122); + // this is purely structural so there should be 1 child + CPPUNIT_ASSERT_EQUAL(size_t(1), pKids1122122->GetElements().size()); + + auto pRefKid11221221 = dynamic_cast(pKids1122122->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid11221221); + auto pObject11221221 = pRefKid11221221->LookupObject(); + CPPUNIT_ASSERT(pObject11221221); + auto pType11221221 = dynamic_cast(pObject11221221->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType11221221); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType11221221->GetValue()); + auto pS11221221 = dynamic_cast(pObject11221221->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS11221221); + CPPUNIT_ASSERT_EQUAL("LI"_ostr, pS11221221->GetValue()); + // LI has 2 children: Lbl and LBody + auto pKids11221221 = dynamic_cast(pObject11221221->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids11221221); + CPPUNIT_ASSERT_EQUAL(size_t(2), pKids11221221->GetElements().size()); + + auto pRefKid112212211 = dynamic_cast(pKids11221221->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid112212211); + auto pObject112212211 = pRefKid112212211->LookupObject(); + CPPUNIT_ASSERT(pObject112212211); + auto pType112212211 = dynamic_cast(pObject112212211->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType112212211); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType112212211->GetValue()); + auto pS112212211 = dynamic_cast(pObject112212211->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS112212211); + CPPUNIT_ASSERT_EQUAL("Lbl"_ostr, pS112212211->GetValue()); + // Lbl has 2 children: the first 2 mcids (in order) + auto pKids112212211 = dynamic_cast(pObject112212211->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids112212211); + CPPUNIT_ASSERT_EQUAL(size_t(2), pKids112212211->GetElements().size()); + + auto pRefKid1122122111 = dynamic_cast(pKids112212211->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid1122122111); + CPPUNIT_ASSERT_EQUAL(mcids[4], int(pRefKid1122122111->GetValue())); + auto pRefKid1122122112 = dynamic_cast(pKids112212211->GetElements()[1]); + CPPUNIT_ASSERT(pRefKid1122122112); + CPPUNIT_ASSERT_EQUAL(mcids[5], int(pRefKid1122122112->GetValue())); + + auto pRefKid112212212 = dynamic_cast(pKids11221221->GetElements()[1]); + CPPUNIT_ASSERT(pRefKid112212212); + auto pObject112212212 = pRefKid112212212->LookupObject(); + CPPUNIT_ASSERT(pObject112212212); + auto pType112212212 = dynamic_cast(pObject112212212->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType112212212); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType112212212->GetValue()); + auto pS112212212 = dynamic_cast(pObject112212212->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS112212212); + CPPUNIT_ASSERT_EQUAL("LBody"_ostr, pS112212212->GetValue()); + // inner LBody has 1 children: paragraph + auto pKids112212212 = dynamic_cast(pObject112212212->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pKids112212212); + CPPUNIT_ASSERT_EQUAL(size_t(1), pKids112212212->GetElements().size()); + + auto pRefKid1122122121 = dynamic_cast(pKids112212212->GetElements()[0]); + CPPUNIT_ASSERT(pRefKid1122122121); + auto pObject1122122121 = pRefKid1122122121->LookupObject(); + CPPUNIT_ASSERT(pObject1122122121); + auto pType1122122121 = dynamic_cast(pObject1122122121->Lookup("Type"_ostr)); + CPPUNIT_ASSERT(pType1122122121); + CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType1122122121->GetValue()); + auto pS1122122121 = dynamic_cast(pObject1122122121->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS1122122121); + CPPUNIT_ASSERT_EQUAL("Standard"_ostr, pS1122122121->GetValue()); + } + } + } + } + CPPUNIT_ASSERT_EQUAL(static_cast(1), nL); +} + +CPPUNIT_TEST_FIXTURE(Test, testTdf143311) +{ + createSwDoc("tdf143311-1.docx"); + CPPUNIT_ASSERT_EQUAL(true, getProperty(getShape(1), "Decorative")); + { + // add another one that's a SdrObject + uno::Reference xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference xShape( + xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + uno::Reference xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("Decorative", uno::Any(true)); + uno::Reference xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPage(xDrawPageSupplier->getDrawPage()); + xDrawPage->add(xShape); + } + // check DOCX filters + saveAndReload("Office Open XML Text"); + CPPUNIT_ASSERT_EQUAL(true, getProperty(getShape(1), "Decorative")); + CPPUNIT_ASSERT_EQUAL(true, getProperty(getShape(2), "Decorative")); + { + // tdf#153925 not imported - check default and set it to test ODF filters + uno::Reference const xStyle(getStyles("FrameStyles")->getByName("Formula"), uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(false, getProperty(xStyle, "Decorative")); + xStyle->setPropertyValue("Decorative", uno::Any(true)); + } + // check ODF filters + saveAndReload("writer8"); + CPPUNIT_ASSERT_EQUAL(true, getProperty(getShape(1), "Decorative")); + CPPUNIT_ASSERT_EQUAL(true, getProperty(getShape(2), "Decorative")); + CPPUNIT_ASSERT_EQUAL(true, getProperty(getStyles("FrameStyles")->getByName("Formula"), "Decorative")); + + // check PDF export + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + // Enable PDF/UA + uno::Sequence aFilterData( + comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } })); + aMediaDescriptor["FilterData"] <<= aFilterData; + css::uno::Reference xStorable(mxComponent, css::uno::UNO_QUERY_THROW); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // The document has one page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + + vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"_ostr); + 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(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<>BDC")) + { + 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_EQUAL(static_cast(25), nTagged); // text in body + // 1 decorative image + 1 decorative shape + 1 pre-existing rectangle border or something + CPPUNIT_ASSERT(nArtifacts >= 3); +} + +void Test::testTextFormField() +{ + const OUString aFilterNames[] = { + "writer8", + "MS Word 97", + "Office Open XML Text", + }; + + for (const OUString& rFilterName : aFilterNames) + { + createSwDoc("text_form_field.odt"); + + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check the document after round trip + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + + // We have two text form fields + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(2), pMarkAccess->getAllMarksCount()); + + // Check whether all fieldmarks are text form fields + for(auto aIter = pMarkAccess->getAllMarksBegin(); aIter != pMarkAccess->getAllMarksEnd(); ++aIter) + { + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(*aIter); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pFieldmark); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), ODF_FORMTEXT, pFieldmark->GetFieldname()); + } + + // In the first paragraph we have an empty text form field with the placeholder spaces + const uno::Reference< text::XTextRange > xPara = getParagraph(1); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldStart"), getProperty(getRun(xPara, 1), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldSeparator"), getProperty(getRun(xPara, 2), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("Text"), getProperty(getRun(xPara, 3), "TextPortionType")); + sal_Unicode vEnSpaces[5] = {8194, 8194, 8194, 8194, 8194}; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(vEnSpaces, 5), getRun(xPara, 3)->getString()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldEnd"), getProperty(getRun(xPara, 4), "TextPortionType")); + + // In the second paragraph we have a set text + const uno::Reference< text::XTextRange > xPara2 = getParagraph(2); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldStart"), getProperty(getRun(xPara2, 1), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldSeparator"), getProperty(getRun(xPara2, 2), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("Text"), getProperty(getRun(xPara2, 3), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("xxxxx"), getRun(xPara2, 3)->getString()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldEnd"), getProperty(getRun(xPara2, 4), "TextPortionType")); + } +} + +void Test::testCheckBoxFormField() +{ + const OUString aFilterNames[] = { + "writer8", + "MS Word 97", + "Office Open XML Text", + }; + + for (const OUString& rFilterName : aFilterNames) + { + createSwDoc("checkbox_form_field.odt"); + + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check the document after round trip + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + + // We have two check box form fields + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(2), pMarkAccess->getAllMarksCount()); + + int nIndex = 0; + for(auto aIter = pMarkAccess->getAllMarksBegin(); aIter != pMarkAccess->getAllMarksEnd(); ++aIter) + { + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(*aIter); + + if(rFilterName == "Office Open XML Text") // OOXML import also generates bookmarks + { + if(!pFieldmark) + continue; + } + + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pFieldmark); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), ODF_FORMCHECKBOX, pFieldmark->GetFieldname()); + ::sw::mark::ICheckboxFieldmark* pCheckBox = dynamic_cast< ::sw::mark::ICheckboxFieldmark* >(pFieldmark); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pCheckBox); + + // The first one is unchecked, the other one is checked + if(nIndex == 0) + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), !pCheckBox->IsChecked()); + else + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pCheckBox->IsChecked()); + ++nIndex; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(2), nIndex); + } +} + +void Test::testDropDownFormField() +{ + const OUString aFilterNames[] = { + "writer8", + "MS Word 97", + "Office Open XML Text", + }; + + for (const OUString& rFilterName : aFilterNames) + { + createSwDoc("dropdown_form_field.odt"); + + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check the document after round trip + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(2), pMarkAccess->getAllMarksCount()); + + int nIndex = 0; + for(auto aIter = pMarkAccess->getAllMarksBegin(); aIter != pMarkAccess->getAllMarksEnd(); ++aIter) + { + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(*aIter); + + if(!pFieldmark) + continue; + + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pFieldmark); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), ODF_FORMDROPDOWN, pFieldmark->GetFieldname()); + + // Check drop down field's parameters. + const sw::mark::IFieldmark::parameter_map_t* const pParameters = pFieldmark->GetParameters(); + css::uno::Sequence vListEntries; + sal_Int32 nSelection = -1; + auto pListEntries = pParameters->find(ODF_FORMDROPDOWN_LISTENTRY); + if (pListEntries != pParameters->end()) + { + pListEntries->second >>= vListEntries; + + if(vListEntries.hasElements()) + { + auto pResult = pParameters->find(ODF_FORMDROPDOWN_RESULT); + if (pResult != pParameters->end()) + { + pResult->second >>= nSelection; + } + } + } + + // The first one is empty + if(nIndex == 0) + { + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), !vListEntries.hasElements()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(-1), nSelection); + } + else // The second one has list and also a selected item + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(4), vListEntries.getLength()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(1), nSelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("1000"), vListEntries[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("2000"), vListEntries[1]); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("3000"), vListEntries[2]); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("4000"), vListEntries[3]); + } + ++nIndex; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(2), nIndex); + } +} + +void Test::testDateFormField() +{ + const OUString aFilterNames[] = { + "writer8", + "Office Open XML Text", + }; + + for (const OUString& rFilterName : aFilterNames) + { + createSwDoc("date_form_field.odt"); + + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check the document after round trip + if (rFilterName == "writer8") + { + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(5), pMarkAccess->getAllMarksCount()); + + int nIndex = 0; + for(auto aIter = pMarkAccess->getAllMarksBegin(); aIter != pMarkAccess->getAllMarksEnd(); ++aIter) + { + ::sw::mark::IDateFieldmark* pFieldmark = dynamic_cast<::sw::mark::IDateFieldmark*>(*aIter); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pFieldmark); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), ODF_FORMDATE, pFieldmark->GetFieldname()); + + // Check date form field's parameters. + const sw::mark::IFieldmark::parameter_map_t* const pParameters = pFieldmark->GetParameters(); + OUString sDateFormat; + auto pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT); + if (pResult != pParameters->end()) + { + pResult->second >>= sDateFormat; + } + + OUString sLang; + pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE); + if (pResult != pParameters->end()) + { + pResult->second >>= sLang; + } + + OUString sCurrentDate = pFieldmark->GetContent(); + + // The first one has the default field content + if(nIndex == 0) + { + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("MM/DD/YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("en-US"), sLang); + sal_Unicode vEnSpaces[ODF_FORMFIELD_DEFAULT_LENGTH] = {8194, 8194, 8194, 8194, 8194}; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(vEnSpaces, 5), sCurrentDate); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), SwNodeOffset(9), pFieldmark->GetMarkStart().GetNodeIndex()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(5), pFieldmark->GetMarkStart().GetContentIndex()); + } + else if (nIndex == 1) // The second has the default format + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("MM/DD/YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("en-US"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("06/12/19"), sCurrentDate); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), SwNodeOffset(9), pFieldmark->GetMarkStart().GetNodeIndex()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(20), pFieldmark->GetMarkStart().GetContentIndex()); + } + else if (nIndex == 2) // The third one has special format + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("[NatNum12 MMMM=abbreviation]YYYY\". \"MMMM D."), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("hu-HU"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("2019. febr. 12."), sCurrentDate); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), SwNodeOffset(9), pFieldmark->GetMarkStart().GetNodeIndex()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(40), pFieldmark->GetMarkStart().GetContentIndex()); + + } + else if (nIndex == 3) // The fourth one has placeholder text + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("D, MMM YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("bm-ML"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("[select date]"), sCurrentDate); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), SwNodeOffset(9), pFieldmark->GetMarkStart().GetNodeIndex()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(62), pFieldmark->GetMarkStart().GetContentIndex()); + + } + else // The last one is really empty + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("MM/DD/YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("en-US"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(""), sCurrentDate); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), SwNodeOffset(9), pFieldmark->GetMarkStart().GetNodeIndex()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(82), pFieldmark->GetMarkStart().GetContentIndex()); + + } + ++nIndex; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(5), nIndex); + } + else + { + // Import from DOCX, so the fieldmark is now a content control. + uno::Reference xEnumAccess(getParagraph(1), uno::UNO_QUERY); + uno::Reference xTextPortions = xEnumAccess->createEnumeration(); + + int nIndex = 0; + while (xTextPortions->hasMoreElements()) + { + uno::Reference xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY); + OUString aPortionType; + xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType; + if (aPortionType != "ContentControl") + { + continue; + } + + uno::Reference xContentControl; + xTextPortion->getPropertyValue("ContentControl") >>= xContentControl; + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + + bool bDate{}; + xContentControlProps->getPropertyValue("Date") >>= bDate; + CPPUNIT_ASSERT(bDate); + + // Check date form field's parameters. + OUString sDateFormat; + xContentControlProps->getPropertyValue("DateFormat") >>= sDateFormat; + + OUString sLang; + xContentControlProps->getPropertyValue("DateLanguage") >>= sLang; + + uno::Reference xContentControlEnumAccess(xContentControl, + uno::UNO_QUERY); + uno::Reference xContentControlEnum + = xContentControlEnumAccess->createEnumeration(); + uno::Reference xContentControlTextPortion(xContentControlEnum->nextElement(), uno::UNO_QUERY); + OUString sCurrentDate = xContentControlTextPortion->getString(); + + // The first one has the default field content + if(nIndex == 0) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("MM/DD/YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("en-US"), sLang); + sal_Unicode vEnSpaces[ODF_FORMFIELD_DEFAULT_LENGTH] = {8194, 8194, 8194, 8194, 8194}; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(vEnSpaces, 5), sCurrentDate); + } + else if (nIndex == 1) // The second has the default format + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("MM/DD/YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("en-US"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("06/12/19"), sCurrentDate); + } + else if (nIndex == 2) // The third one has special format + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("[NatNum12 MMMM=abbreviation]YYYY\". \"MMMM D."), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("hu-HU"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("2019. febr. 12."), sCurrentDate); + } + else if (nIndex == 3) // The fourth one has placeholder text + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("D, MMM YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("bm-ML"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("[select date]"), sCurrentDate); + } + else // The last one is really empty + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("MM/DD/YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("en-US"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(""), sCurrentDate); + } + ++nIndex; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(5), nIndex); + } + } +} + +void Test::testDateFormFieldCharacterFormatting() +{ + const OUString aFilterNames[] = { + "writer8", + "Office Open XML Text", + }; + + for (const OUString& rFilterName : aFilterNames) + { + createSwDoc("date_form_field_char_formatting.odt"); + + const OString sFailedMessage = OString::Concat("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + saveAndReload(rFilterName); + + // Check the document after round trip + if (rFilterName == "writer8") + { + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + + // Check that we have the field at the right place + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(1), pMarkAccess->getAllMarksCount()); + ::sw::mark::IDateFieldmark* pFieldmark = dynamic_cast<::sw::mark::IDateFieldmark*>(*pMarkAccess->getAllMarksBegin()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pFieldmark); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), ODF_FORMDATE, pFieldmark->GetFieldname()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(0), pFieldmark->GetMarkStart().GetContentIndex()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(11), pFieldmark->GetMarkEnd().GetContentIndex()); + + // We have one date field, first half of the field has bold character weight and second part has red character color + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), awt::FontWeight::BOLD, getProperty(getRun(getParagraph(1), 3), "CharWeight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_AUTO, getProperty(getRun(getParagraph(1), 3), "CharColor")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), awt::FontWeight::NORMAL, getProperty(getRun(getParagraph(1), 4), "CharWeight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), Color(0xff0000), getProperty(getRun(getParagraph(1), 4), "CharColor")); + } + else + { + uno::Reference xTextPortion(getRun(getParagraph(1), 1), uno::UNO_QUERY); + OUString aPortionType; + xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType; + CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType); + + uno::Reference xContentControl; + xTextPortion->getPropertyValue("ContentControl") >>= xContentControl; + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + bool bDate{}; + xContentControlProps->getPropertyValue("Date") >>= bDate; + CPPUNIT_ASSERT(bDate); + + uno::Reference xContentControlEnumAccess(xContentControl, + uno::UNO_QUERY); + uno::Reference xContentControlEnum + = xContentControlEnumAccess->createEnumeration(); + xTextPortion.set(xContentControlEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), awt::FontWeight::BOLD, getProperty(xTextPortion, "CharWeight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), COL_AUTO, getProperty(xTextPortion, "CharColor")); + xTextPortion.set(xContentControlEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), awt::FontWeight::NORMAL, getProperty(xTextPortion, "CharWeight")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), Color(0xff0000), getProperty(xTextPortion, "CharColor")); + } + } +} + +void Test::testSvgImageSupport() +{ + OUString aFilterNames[] = { + "writer8", + "Office Open XML Text", + }; + + for (OUString const & rFilterName : aFilterNames) + { + // Use case to import a document containing a SVG image, export in target format, import and check if the + // SVG image is present and as expected in the document + + // Import ODT file + createSwDoc("SvgImageTest.odt"); + + // Export the document in target format and import again + saveAndReload(rFilterName); + + // Prepare fail message (writing which import/export filter was used) + const OString sFailedMessage = "Failed on filter: "_ostr + rFilterName.toUtf8(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 1, getShapes()); + + // Get the image + uno::Reference xImage(getShape(1), uno::UNO_QUERY); + uno::Reference xPropertySet(xImage, uno::UNO_QUERY_THROW); + + // Convert to a XGraphic + uno::Reference xGraphic; + xPropertySet->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); + + // Access the Graphic + Graphic aGraphic(xGraphic); + + // Check if it contian a VectorGraphicData struct + auto pVectorGraphic = aGraphic.getVectorGraphicData(); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pVectorGraphic); + + // Which should be of type SVG, which means we have a SVG file + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), VectorGraphicDataType::Svg, pVectorGraphic->getType()); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3