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 --- .../qa/unit/data/FillAndStrokeThemeColorTest.fodp | 783 ++++++++++++ xmloff/qa/unit/data/MCGR_Border_restoration.pptx | Bin 0 -> 26853 bytes xmloff/qa/unit/data/MCGR_OldToNew.odg | Bin 0 -> 14577 bytes xmloff/qa/unit/data/MCGR_OldToNew_opacity.odg | Bin 0 -> 16806 bytes .../data/MCGR_TransparencyBorder_restoration.pptx | Bin 0 -> 15436 bytes xmloff/qa/unit/data/MCGR_threeStops.fodt | 317 +++++ .../data/Reference-ThemeColors-TextAndFill.pptx | Bin 0 -> 34341 bytes xmloff/qa/unit/data/ReferenceShapeFill.pptx | Bin 0 -> 14310 bytes xmloff/qa/unit/data/clearing-break.fodt | 28 + xmloff/qa/unit/data/comment-table-border.fodt | 16 + xmloff/qa/unit/data/content-control-alias.fodt | 8 + xmloff/qa/unit/data/content-control-checkbox.fodt | 8 + xmloff/qa/unit/data/content-control-combo-box.fodt | 8 + xmloff/qa/unit/data/content-control-date.fodt | 8 + xmloff/qa/unit/data/content-control-dropdown.docx | Bin 0 -> 65391 bytes xmloff/qa/unit/data/content-control-dropdown.fodt | 8 + xmloff/qa/unit/data/content-control-picture.fodt | 13 + .../qa/unit/data/content-control-plain-text.fodt | 8 + xmloff/qa/unit/data/content-control.fodt | 8 + xmloff/qa/unit/data/continue-numbering-word.odt | Bin 0 -> 6151 bytes .../qa/unit/data/differentListStylesInOneList.fodt | 47 + xmloff/qa/unit/data/fill-image-base64.fodg | 230 ++++ .../qa/unit/data/floattable-wrap-all-pages2.fodt | 41 + xmloff/qa/unit/data/floattable.fodt | 31 + xmloff/qa/unit/data/list-id.fodt | 23 + xmloff/qa/unit/data/listRestartAfterBreak.fodt | 25 + xmloff/qa/unit/data/mail-merge-editeng.odt | Bin 0 -> 9382 bytes xmloff/qa/unit/data/nested-spans.odt | Bin 0 -> 6381 bytes xmloff/qa/unit/data/para-style-list-level.fodt | 14 + .../qa/unit/data/paragraph-tab-stop-distance.fodp | 19 + xmloff/qa/unit/data/rtl-gutter.fodt | 16 + xmloff/qa/unit/data/scale-width-redline.fodt | 170 +++ xmloff/qa/unit/data/table-in-shape.fodt | 22 + xmloff/qa/unit/data/tdf141301_Extrusion_Skew.odg | Bin 0 -> 9838 bytes .../data/tdf145700_3D_metal_type_MSCompatible.doc | Bin 0 -> 27136 bytes .../unit/data/tdf147580_extrusion-specularity.doc | Bin 0 -> 27136 bytes xmloff/qa/unit/data/tdf148714_CurvedArrowsOld.odp | Bin 0 -> 17679 bytes xmloff/qa/unit/data/tdf149551_verticalText.pptx | Bin 0 -> 16078 bytes .../qa/unit/data/tdf150407_PosRelBottomMargin.docx | Bin 0 -> 17439 bytes xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx | Bin 0 -> 17432 bytes .../unit/data/tdf150407_WritingModeBTLR_style.odt | Bin 0 -> 11181 bytes .../tdf155549_MCGR_AxialGradientCompatible.odt | Bin 0 -> 12891 bytes .../tdf155549_MCGR_AxialTransparencyCompatible.odt | Bin 0 -> 22129 bytes xmloff/qa/unit/data/tdf157018_CustomTheme.fodg | 338 +++++ xmloff/qa/unit/data/textbox-loss.docx | Bin 0 -> 42192 bytes xmloff/qa/unit/data/theme.fodp | 997 +++++++++++++++ xmloff/qa/unit/data/video-snapshot.odp | Bin 0 -> 17605 bytes xmloff/qa/unit/draw.cxx | 815 ++++++++++++ xmloff/qa/unit/style.cxx | 663 ++++++++++ xmloff/qa/unit/text.cxx | 1291 ++++++++++++++++++++ xmloff/qa/unit/text/txtprmap.cxx | 87 ++ xmloff/qa/unit/tokenmap-test.cxx | 92 ++ xmloff/qa/unit/uxmloff.cxx | 233 ++++ 53 files changed, 6367 insertions(+) create mode 100644 xmloff/qa/unit/data/FillAndStrokeThemeColorTest.fodp create mode 100644 xmloff/qa/unit/data/MCGR_Border_restoration.pptx create mode 100644 xmloff/qa/unit/data/MCGR_OldToNew.odg create mode 100644 xmloff/qa/unit/data/MCGR_OldToNew_opacity.odg create mode 100644 xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx create mode 100644 xmloff/qa/unit/data/MCGR_threeStops.fodt create mode 100644 xmloff/qa/unit/data/Reference-ThemeColors-TextAndFill.pptx create mode 100644 xmloff/qa/unit/data/ReferenceShapeFill.pptx create mode 100644 xmloff/qa/unit/data/clearing-break.fodt create mode 100644 xmloff/qa/unit/data/comment-table-border.fodt create mode 100644 xmloff/qa/unit/data/content-control-alias.fodt create mode 100644 xmloff/qa/unit/data/content-control-checkbox.fodt create mode 100644 xmloff/qa/unit/data/content-control-combo-box.fodt create mode 100644 xmloff/qa/unit/data/content-control-date.fodt create mode 100644 xmloff/qa/unit/data/content-control-dropdown.docx create mode 100644 xmloff/qa/unit/data/content-control-dropdown.fodt create mode 100644 xmloff/qa/unit/data/content-control-picture.fodt create mode 100644 xmloff/qa/unit/data/content-control-plain-text.fodt create mode 100644 xmloff/qa/unit/data/content-control.fodt create mode 100644 xmloff/qa/unit/data/continue-numbering-word.odt create mode 100644 xmloff/qa/unit/data/differentListStylesInOneList.fodt create mode 100644 xmloff/qa/unit/data/fill-image-base64.fodg create mode 100644 xmloff/qa/unit/data/floattable-wrap-all-pages2.fodt create mode 100644 xmloff/qa/unit/data/floattable.fodt create mode 100644 xmloff/qa/unit/data/list-id.fodt create mode 100644 xmloff/qa/unit/data/listRestartAfterBreak.fodt create mode 100644 xmloff/qa/unit/data/mail-merge-editeng.odt create mode 100644 xmloff/qa/unit/data/nested-spans.odt create mode 100644 xmloff/qa/unit/data/para-style-list-level.fodt create mode 100644 xmloff/qa/unit/data/paragraph-tab-stop-distance.fodp create mode 100644 xmloff/qa/unit/data/rtl-gutter.fodt create mode 100644 xmloff/qa/unit/data/scale-width-redline.fodt create mode 100644 xmloff/qa/unit/data/table-in-shape.fodt create mode 100644 xmloff/qa/unit/data/tdf141301_Extrusion_Skew.odg create mode 100644 xmloff/qa/unit/data/tdf145700_3D_metal_type_MSCompatible.doc create mode 100644 xmloff/qa/unit/data/tdf147580_extrusion-specularity.doc create mode 100644 xmloff/qa/unit/data/tdf148714_CurvedArrowsOld.odp create mode 100644 xmloff/qa/unit/data/tdf149551_verticalText.pptx create mode 100644 xmloff/qa/unit/data/tdf150407_PosRelBottomMargin.docx create mode 100644 xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx create mode 100644 xmloff/qa/unit/data/tdf150407_WritingModeBTLR_style.odt create mode 100644 xmloff/qa/unit/data/tdf155549_MCGR_AxialGradientCompatible.odt create mode 100644 xmloff/qa/unit/data/tdf155549_MCGR_AxialTransparencyCompatible.odt create mode 100644 xmloff/qa/unit/data/tdf157018_CustomTheme.fodg create mode 100644 xmloff/qa/unit/data/textbox-loss.docx create mode 100644 xmloff/qa/unit/data/theme.fodp create mode 100644 xmloff/qa/unit/data/video-snapshot.odp create mode 100644 xmloff/qa/unit/draw.cxx create mode 100644 xmloff/qa/unit/style.cxx create mode 100644 xmloff/qa/unit/text.cxx create mode 100644 xmloff/qa/unit/text/txtprmap.cxx create mode 100644 xmloff/qa/unit/tokenmap-test.cxx create mode 100644 xmloff/qa/unit/uxmloff.cxx (limited to 'xmloff/qa/unit') diff --git a/xmloff/qa/unit/data/FillAndStrokeThemeColorTest.fodp b/xmloff/qa/unit/data/FillAndStrokeThemeColorTest.fodp new file mode 100644 index 0000000000..1839fbdf2e --- /dev/null +++ b/xmloff/qa/unit/data/FillAndStrokeThemeColorTest.fodp @@ -0,0 +1,783 @@ + + + + 2023-08-12T00:18:29.4926421482023-08-14T22:51:14.327461242PT11M42S7LibreOfficeDev/24.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/1778766b8ce5110eee4a5c5ce1821108bd0adde7 + + + 0 + 0 + 14099 + 9999 + + + view1 + false + false + true + true + true + true + false + false + true + 1500 + false + Hw== + Hw== + + false + true + false + 0 + 0 + false + true + true + 4 + 0 + -229 + -8319 + 44980 + 16334 + 2000 + 2000 + 500 + 500 + 2000 + 4 + 2000 + 4 + false + 1500 + true + false + false + false + false + + + + + 6 + false + false + false + false + false + 0 + false + false + true + true + true + true + false + true + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.soe + true + true + tAH+/0dlbmVyaWMgUHJpbnRlcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU0dFTlBSVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAMAoAAAAAAAAAAEAAhSAAAEdAAASm9iRGF0YSAxCnByaW50ZXI9R2VuZXJpYyBQcmludGVyCm9yaWVudGF0aW9uPVBvcnRyYWl0CmNvcGllcz0xCmNvbGxhdGU9ZmFsc2UKbWFyZ2luYWRqdXN0bWVudD0wLDAsJzAsMApjb2xvcmRlcHRoPTI0CmNvbG9yZGV2aWNlPTAKUFBEQ29udGV4dERhdGEKUGFnZVNpemU6QTQAABIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmYMAFBSSU5URVJfTkFNRQ8AR2VuZXJpYyBQcmludGVyCwBEUklWRVJfTkFNRQcAU0dFTlBSVA== + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.sog + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.sob + 1250 + Generic Printer + $(brandbaseurl)/share/palette%3B$(userpath)/config/Theme%20colors.soc + 4 + false + 0 + false + 0 + false + false + low-resolution + true + false + false + true + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.sod + false + false + true + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.soh + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <number> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <number> + + + + + + + + + + + + + + + + + + + + + + + + + <number> + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xmloff/qa/unit/data/MCGR_Border_restoration.pptx b/xmloff/qa/unit/data/MCGR_Border_restoration.pptx new file mode 100644 index 0000000000..b43e15145f Binary files /dev/null and b/xmloff/qa/unit/data/MCGR_Border_restoration.pptx differ diff --git a/xmloff/qa/unit/data/MCGR_OldToNew.odg b/xmloff/qa/unit/data/MCGR_OldToNew.odg new file mode 100644 index 0000000000..7db627d0c2 Binary files /dev/null and b/xmloff/qa/unit/data/MCGR_OldToNew.odg differ diff --git a/xmloff/qa/unit/data/MCGR_OldToNew_opacity.odg b/xmloff/qa/unit/data/MCGR_OldToNew_opacity.odg new file mode 100644 index 0000000000..8b64a9037e Binary files /dev/null and b/xmloff/qa/unit/data/MCGR_OldToNew_opacity.odg differ diff --git a/xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx b/xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx new file mode 100644 index 0000000000..f32c4d5e2b Binary files /dev/null and b/xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx differ diff --git a/xmloff/qa/unit/data/MCGR_threeStops.fodt b/xmloff/qa/unit/data/MCGR_threeStops.fodt new file mode 100644 index 0000000000..ac9c9978e2 --- /dev/null +++ b/xmloff/qa/unit/data/MCGR_threeStops.fodt @@ -0,0 +1,317 @@ + + + + Regina Henschel2023-04-18T23:09:21.4340000002023-04-18T23:28:52.397000000Regina HenschelPT9M47S3B2020/7.6.0.0.alpha0$Windows_X86_64 LibreOffice_project/bcf20273b7036cae9b58d8f452933c0c8d0b8e47 + + + 0 + 0 + 27349 + 9527 + true + false + + + view2 + 6562 + 2501 + 0 + 0 + 27347 + 9525 + 0 + 1 + false + 100 + true + false + false + false + false + false + + + + + true + + false + false + false + false + true + 1 + true + false + false + false + + false + + false + false + false + + 0 + false + true + true + false + false + false + + 0 + + true + high-resolution + false + false + false + false + true + false + false + true + false + false + true + true + false + false + false + true + false + true + false + false + true + false + false + false + false + false + false + 447710 + 238319 + false + false + false + true + false + false + true + true + false + true + true + false + false + false + false + false + true + false + true + false + false + false + false + false + true + 0 + true + false + false + false + true + false + 0 + true + false + true + true + true + true + false + false + false + false + false + true + + false + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Dummy + + + \ No newline at end of file diff --git a/xmloff/qa/unit/data/Reference-ThemeColors-TextAndFill.pptx b/xmloff/qa/unit/data/Reference-ThemeColors-TextAndFill.pptx new file mode 100644 index 0000000000..b2319fe6ea Binary files /dev/null and b/xmloff/qa/unit/data/Reference-ThemeColors-TextAndFill.pptx differ diff --git a/xmloff/qa/unit/data/ReferenceShapeFill.pptx b/xmloff/qa/unit/data/ReferenceShapeFill.pptx new file mode 100644 index 0000000000..782a54d7b2 Binary files /dev/null and b/xmloff/qa/unit/data/ReferenceShapeFill.pptx differ diff --git a/xmloff/qa/unit/data/clearing-break.fodt b/xmloff/qa/unit/data/clearing-break.fodt new file mode 100644 index 0000000000..b80ff0d74b --- /dev/null +++ b/xmloff/qa/unit/data/clearing-break.fodt @@ -0,0 +1,28 @@ + + + + + + + + + + iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAABGdBTUEAALGPC/xhBQAAAAFz + UkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA + AAJiS0dEAACqjSMyAAAACW9GRnMAAAAGAAAAAAAMc1XTAAAACXBIWXMAAA3XAAAN1wFCKJt4 + AAAACXZwQWcAAABMAAAAQACdMTgbAAABzUlEQVRo3u3ZPU/CQBjA8X+Jxs3ESUDj4iK+LA5+ + BBfjqBE1cXB2MlFAEqMgxvhNNL4sLsK3UPQL6ObkoAETz+FKW2mxCPRYnucWUu76/OC59C49 + cGOCKqrD9kHRc6ddPv7oW2WCwMh0nF63Myz7Tm8hPTNu0pgHMER3scepTbgK6enJNND83RLn + /878yRaPmgBZFDuMsNLeWB9gmFQHP77MIg9gsYciR50NFKvtjIy10yk84pSZA7DYpwR8scmF + QQCMuoQMpzbh0iAARrlnVn90CWHTsZcAiHPPdINQAuqsc2MQAAnKDUKWEhZ10twaBEDSJWQo + YlFj7S9CzwEegkXWIbQsRAQASFJhpplwbRAACS+hANRJBxMiAkDcJeQ4sQkBhYgMoJ+Ozlwo + 2YQ7AJ6CRxyiUGnVy3hVKb0Af9v7hUG2Wy9TEQCUelFTDULB2S+YKYGOMcpM6UIccOQnRA6A + cSp6ibfI+wkGADBGpTEd8xz1AaAfTQ7huA8AvUw5hVjuA0D/C5OaMN8XACRZ8F0zCggKAQhA + AAIQgAAEIAABCEAAAhCAAAQgAAH4zg3feY4w3Xs44M5+oW0qvCWoGcvaIlM3x/f/ab+O738A + hOCNQr34oD4AAAAldEVYdGNyZWF0ZS1kYXRlADIwMTAtMTItMjBUMTc6MDg6MzYrMDE6MDB6 + 5RscAAAAJXRFWHRtb2RpZnktZGF0ZQAyMDEwLTEyLTIwVDE3OjA4OjM3KzAxOjAwgyNmnAAA + AABJRU5ErkJggg== + foobar + + + diff --git a/xmloff/qa/unit/data/comment-table-border.fodt b/xmloff/qa/unit/data/comment-table-border.fodt new file mode 100644 index 0000000000..29f54da9af --- /dev/null +++ b/xmloff/qa/unit/data/comment-table-border.fodt @@ -0,0 +1,16 @@ + + + + + + + + + Axb + + + + bZ + + + diff --git a/xmloff/qa/unit/data/content-control-alias.fodt b/xmloff/qa/unit/data/content-control-alias.fodt new file mode 100644 index 0000000000..0742610ca6 --- /dev/null +++ b/xmloff/qa/unit/data/content-control-alias.fodt @@ -0,0 +1,8 @@ + + + + + test + + + diff --git a/xmloff/qa/unit/data/content-control-checkbox.fodt b/xmloff/qa/unit/data/content-control-checkbox.fodt new file mode 100644 index 0000000000..59c333ab9d --- /dev/null +++ b/xmloff/qa/unit/data/content-control-checkbox.fodt @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/xmloff/qa/unit/data/content-control-combo-box.fodt b/xmloff/qa/unit/data/content-control-combo-box.fodt new file mode 100644 index 0000000000..03f6911fb7 --- /dev/null +++ b/xmloff/qa/unit/data/content-control-combo-box.fodt @@ -0,0 +1,8 @@ + + + + + choose a color + + + diff --git a/xmloff/qa/unit/data/content-control-date.fodt b/xmloff/qa/unit/data/content-control-date.fodt new file mode 100644 index 0000000000..c49e51339c --- /dev/null +++ b/xmloff/qa/unit/data/content-control-date.fodt @@ -0,0 +1,8 @@ + + + + + choose a date + + + diff --git a/xmloff/qa/unit/data/content-control-dropdown.docx b/xmloff/qa/unit/data/content-control-dropdown.docx new file mode 100644 index 0000000000..1391c90f1a Binary files /dev/null and b/xmloff/qa/unit/data/content-control-dropdown.docx differ diff --git a/xmloff/qa/unit/data/content-control-dropdown.fodt b/xmloff/qa/unit/data/content-control-dropdown.fodt new file mode 100644 index 0000000000..73007b2c7c --- /dev/null +++ b/xmloff/qa/unit/data/content-control-dropdown.fodt @@ -0,0 +1,8 @@ + + + + + choose a color + + + diff --git a/xmloff/qa/unit/data/content-control-picture.fodt b/xmloff/qa/unit/data/content-control-picture.fodt new file mode 100644 index 0000000000..ae47bfa0df --- /dev/null +++ b/xmloff/qa/unit/data/content-control-picture.fodt @@ -0,0 +1,13 @@ + + + + + + iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAAEElEQVR4nGJgAQAAAP//AwAA + BgAFV7+r1AAAAABJRU5ErkJggg== + + + + + + diff --git a/xmloff/qa/unit/data/content-control-plain-text.fodt b/xmloff/qa/unit/data/content-control-plain-text.fodt new file mode 100644 index 0000000000..03dbdc8a7a --- /dev/null +++ b/xmloff/qa/unit/data/content-control-plain-text.fodt @@ -0,0 +1,8 @@ + + + + + test + + + diff --git a/xmloff/qa/unit/data/content-control.fodt b/xmloff/qa/unit/data/content-control.fodt new file mode 100644 index 0000000000..97769c662b --- /dev/null +++ b/xmloff/qa/unit/data/content-control.fodt @@ -0,0 +1,8 @@ + + + + + test + + + diff --git a/xmloff/qa/unit/data/continue-numbering-word.odt b/xmloff/qa/unit/data/continue-numbering-word.odt new file mode 100644 index 0000000000..278a1fa656 Binary files /dev/null and b/xmloff/qa/unit/data/continue-numbering-word.odt differ diff --git a/xmloff/qa/unit/data/differentListStylesInOneList.fodt b/xmloff/qa/unit/data/differentListStylesInOneList.fodt new file mode 100644 index 0000000000..5f90135fbb --- /dev/null +++ b/xmloff/qa/unit/data/differentListStylesInOneList.fodt @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + Item1 (ListStyleOne) + + + + + + Item2 (ListStyleOne) + + + + + + Item3 (ListStyleAnother) + + + + + + Item4 (ListStyleOne) + + + + + \ No newline at end of file diff --git a/xmloff/qa/unit/data/fill-image-base64.fodg b/xmloff/qa/unit/data/fill-image-base64.fodg new file mode 100644 index 0000000000..ce0df9d1dd --- /dev/null +++ b/xmloff/qa/unit/data/fill-image-base64.fodg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAABGdBTUEAALGPC/xhBQAAAAFz + UkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA + AAJiS0dEAACqjSMyAAAACW9GRnMAAAAGAAAAAAAMc1XTAAAACXBIWXMAAA3XAAAN1wFCKJt4 + AAAACXZwQWcAAABMAAAAQACdMTgbAAABzUlEQVRo3u3ZPU/CQBjA8X+Jxs3ESUDj4iK+LA5+ + BBfjqBE1cXB2MlFAEqMgxvhNNL4sLsK3UPQL6ObkoAETz+FKW2mxCPRYnucWUu76/OC59C49 + cGOCKqrD9kHRc6ddPv7oW2WCwMh0nF63Myz7Tm8hPTNu0pgHMER3scepTbgK6enJNND83RLn + /878yRaPmgBZFDuMsNLeWB9gmFQHP77MIg9gsYciR50NFKvtjIy10yk84pSZA7DYpwR8scmF + QQCMuoQMpzbh0iAARrlnVn90CWHTsZcAiHPPdINQAuqsc2MQAAnKDUKWEhZ10twaBEDSJWQo + YlFj7S9CzwEegkXWIbQsRAQASFJhpplwbRAACS+hANRJBxMiAkDcJeQ4sQkBhYgMoJ+Ozlwo + 2YQ7AJ6CRxyiUGnVy3hVKb0Af9v7hUG2Wy9TEQCUelFTDULB2S+YKYGOMcpM6UIccOQnRA6A + cSp6ibfI+wkGADBGpTEd8xz1AaAfTQ7huA8AvUw5hVjuA0D/C5OaMN8XACRZ8F0zCggKAQhA + AAIQgAAEIAABCEAAAhCAAAQgAAH4zg3feY4w3Xs44M5+oW0qvCWoGcvaIlM3x/f/ab+O738A + hOCNQr34oD4AAAAldEVYdGNyZWF0ZS1kYXRlADIwMTAtMTItMjBUMTc6MDg6MzYrMDE6MDB6 + 5RscAAAAJXRFWHRtb2RpZnktZGF0ZQAyMDEwLTEyLTIwVDE3OjA4OjM3KzAxOjAwgyNmnAAA + AABJRU5ErkJggg== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xmloff/qa/unit/data/floattable-wrap-all-pages2.fodt b/xmloff/qa/unit/data/floattable-wrap-all-pages2.fodt new file mode 100644 index 0000000000..e8289d6653 --- /dev/null +++ b/xmloff/qa/unit/data/floattable-wrap-all-pages2.fodt @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + First paragraph + A1A2He heard quiet steps behind him. That didn't bode well. Who could be following him this late at night and in this deadbeat part of town? And at this particular moment, just after he pulled off the big time and was making off with the greenbacks. Was there another crook who'd had the same idea, and was now watching him and waiting for a chance to grab the fruit of his labor? Or did the steps behind him mean that one of many law officers in town was on to him and just waiting to pounce and snap those cuffs on his wrists? He nervously looked all around. Suddenly he saw the alley. Like lightning he darted off to the left and disappeared between the two warehouses almost falling over the trash can lying in the middle of the sidewalk. + + + diff --git a/xmloff/qa/unit/data/floattable.fodt b/xmloff/qa/unit/data/floattable.fodt new file mode 100644 index 0000000000..927d14b757 --- /dev/null +++ b/xmloff/qa/unit/data/floattable.fodt @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + A1A2anchor text + + + diff --git a/xmloff/qa/unit/data/list-id.fodt b/xmloff/qa/unit/data/list-id.fodt new file mode 100644 index 0000000000..377dbcbd64 --- /dev/null +++ b/xmloff/qa/unit/data/list-id.fodt @@ -0,0 +1,23 @@ + + + + + + + + + + + + First + + + Second + + + Third + + + + + diff --git a/xmloff/qa/unit/data/listRestartAfterBreak.fodt b/xmloff/qa/unit/data/listRestartAfterBreak.fodt new file mode 100644 index 0000000000..7ae5c84d70 --- /dev/null +++ b/xmloff/qa/unit/data/listRestartAfterBreak.fodt @@ -0,0 +1,25 @@ + + + + + + + + Item1 + + + + + + Item2 + + + + + + Item3 (restarted) + + + + + \ No newline at end of file diff --git a/xmloff/qa/unit/data/mail-merge-editeng.odt b/xmloff/qa/unit/data/mail-merge-editeng.odt new file mode 100644 index 0000000000..e6466e44e0 Binary files /dev/null and b/xmloff/qa/unit/data/mail-merge-editeng.odt differ diff --git a/xmloff/qa/unit/data/nested-spans.odt b/xmloff/qa/unit/data/nested-spans.odt new file mode 100644 index 0000000000..3e7b1dc9eb Binary files /dev/null and b/xmloff/qa/unit/data/nested-spans.odt differ diff --git a/xmloff/qa/unit/data/para-style-list-level.fodt b/xmloff/qa/unit/data/para-style-list-level.fodt new file mode 100644 index 0000000000..3cf0fd6f53 --- /dev/null +++ b/xmloff/qa/unit/data/para-style-list-level.fodt @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/xmloff/qa/unit/data/paragraph-tab-stop-distance.fodp b/xmloff/qa/unit/data/paragraph-tab-stop-distance.fodp new file mode 100644 index 0000000000..f51e75b796 --- /dev/null +++ b/xmloff/qa/unit/data/paragraph-tab-stop-distance.fodp @@ -0,0 +1,19 @@ + + + + + + + + + + + + + starttab1tab2tab4 + + + + + + diff --git a/xmloff/qa/unit/data/rtl-gutter.fodt b/xmloff/qa/unit/data/rtl-gutter.fodt new file mode 100644 index 0000000000..81524fcede --- /dev/null +++ b/xmloff/qa/unit/data/rtl-gutter.fodt @@ -0,0 +1,16 @@ + + + + + + + + + + + + + hello + + + diff --git a/xmloff/qa/unit/data/scale-width-redline.fodt b/xmloff/qa/unit/data/scale-width-redline.fodt new file mode 100644 index 0000000000..6b98c6e27a --- /dev/null +++ b/xmloff/qa/unit/data/scale-width-redline.fodt @@ -0,0 +1,170 @@ + + + LibreOfficeDev/7.6.0.0.alpha0$Linux_X86_64 LibreOffice_project/2e076661cf81225e390a3f5c86171eebb74ebbedGetting Started with LibreOffice 4.22010-01-04T08:31:18369P2DT11H48M52SJean Hollis Weber2023-01-23T16:28:26.015905461 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + before image + + + + iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAAEElEQVR4nGJgAQAAAP//AwAA + BgAFV7+r1AAAAABJRU5ErkJggg== + + + + Figure 1: caption + + + after image + + + diff --git a/xmloff/qa/unit/data/table-in-shape.fodt b/xmloff/qa/unit/data/table-in-shape.fodt new file mode 100644 index 0000000000..44c2bcb05d --- /dev/null +++ b/xmloff/qa/unit/data/table-in-shape.fodt @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + A1 + + + diff --git a/xmloff/qa/unit/data/tdf141301_Extrusion_Skew.odg b/xmloff/qa/unit/data/tdf141301_Extrusion_Skew.odg new file mode 100644 index 0000000000..757289d438 Binary files /dev/null and b/xmloff/qa/unit/data/tdf141301_Extrusion_Skew.odg differ diff --git a/xmloff/qa/unit/data/tdf145700_3D_metal_type_MSCompatible.doc b/xmloff/qa/unit/data/tdf145700_3D_metal_type_MSCompatible.doc new file mode 100644 index 0000000000..99c433654d Binary files /dev/null and b/xmloff/qa/unit/data/tdf145700_3D_metal_type_MSCompatible.doc differ diff --git a/xmloff/qa/unit/data/tdf147580_extrusion-specularity.doc b/xmloff/qa/unit/data/tdf147580_extrusion-specularity.doc new file mode 100644 index 0000000000..9efe793d3d Binary files /dev/null and b/xmloff/qa/unit/data/tdf147580_extrusion-specularity.doc differ diff --git a/xmloff/qa/unit/data/tdf148714_CurvedArrowsOld.odp b/xmloff/qa/unit/data/tdf148714_CurvedArrowsOld.odp new file mode 100644 index 0000000000..94a4e0b3a2 Binary files /dev/null and b/xmloff/qa/unit/data/tdf148714_CurvedArrowsOld.odp differ diff --git a/xmloff/qa/unit/data/tdf149551_verticalText.pptx b/xmloff/qa/unit/data/tdf149551_verticalText.pptx new file mode 100644 index 0000000000..b142a2e834 Binary files /dev/null and b/xmloff/qa/unit/data/tdf149551_verticalText.pptx differ diff --git a/xmloff/qa/unit/data/tdf150407_PosRelBottomMargin.docx b/xmloff/qa/unit/data/tdf150407_PosRelBottomMargin.docx new file mode 100644 index 0000000000..0264f89f98 Binary files /dev/null and b/xmloff/qa/unit/data/tdf150407_PosRelBottomMargin.docx differ diff --git a/xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx b/xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx new file mode 100644 index 0000000000..48f9815062 Binary files /dev/null and b/xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx differ diff --git a/xmloff/qa/unit/data/tdf150407_WritingModeBTLR_style.odt b/xmloff/qa/unit/data/tdf150407_WritingModeBTLR_style.odt new file mode 100644 index 0000000000..2ad2ca1219 Binary files /dev/null and b/xmloff/qa/unit/data/tdf150407_WritingModeBTLR_style.odt differ diff --git a/xmloff/qa/unit/data/tdf155549_MCGR_AxialGradientCompatible.odt b/xmloff/qa/unit/data/tdf155549_MCGR_AxialGradientCompatible.odt new file mode 100644 index 0000000000..ca9f49e906 Binary files /dev/null and b/xmloff/qa/unit/data/tdf155549_MCGR_AxialGradientCompatible.odt differ diff --git a/xmloff/qa/unit/data/tdf155549_MCGR_AxialTransparencyCompatible.odt b/xmloff/qa/unit/data/tdf155549_MCGR_AxialTransparencyCompatible.odt new file mode 100644 index 0000000000..5fda0c063f Binary files /dev/null and b/xmloff/qa/unit/data/tdf155549_MCGR_AxialTransparencyCompatible.odt differ diff --git a/xmloff/qa/unit/data/tdf157018_CustomTheme.fodg b/xmloff/qa/unit/data/tdf157018_CustomTheme.fodg new file mode 100644 index 0000000000..49673ca667 --- /dev/null +++ b/xmloff/qa/unit/data/tdf157018_CustomTheme.fodg @@ -0,0 +1,338 @@ + + + + 2023-08-29T21:49:18.192000000 + PT1S + 1 + B2020/24.2.0.0.alpha0$Windows_X86_64 LibreOffice_project/aa3eea21fcf302ef4ddbba5841037378945f9d5e + + + + + 13970 + 10795 + 0 + 0 + + + view1 + false + false + true + true + false + false + false + false + true + 1500 + false + Hw== + Hw== + + false + true + true + 0 + 0 + true + true + true + 4 + 0 + -407 + -9321 + 40625 + 29064 + 1270 + 1270 + 317 + 317 + 1270 + 4 + 1270 + 4 + false + 1500 + true + false + false + false + false + + + + + true + 1270 + EPSON6FC99C (WP-4025 Series) + iAv+/0VQU09ONkZDOTlDIChXUC00MDI1IFNlcmllcykAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARVBTT04gV1AtNDAyNSBTZXJpZXMAAAAAAAAAAAAAAAAWAAEAWgoAAAAAAAAEAAhSAAAEdAAAM1ROVwAAAAAKAEUAUABTAE8ATgA2AEYAQwA5ADkAQwAgACgAVwBQAC0ANAAwADIANQAgAFMAZQByAGkAZQBzACkAAAAAAAAAAAABBAAB3AB0CQ+bgAcBAAkAmgs0CGQAAQAHAFgCAgABAFgCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0CQAAAQEBAQABAAABAAAAAAAAAAAAAAA4AAAAfAgAALQIAABAAAAA9AgAAIAAAAAAAAAAAAAAAAMABwRFAFAAUwBPAE4AIABXAFAALQA0ADAAMgA1ACAAUwBlAHIAaQBlAHMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABYAgAAAAAAAAAAAAABAAAAAgAAAAAAAQBYAlgCBwAAAAAACQA0CJoLHgAeAB4AHgA0CJoLOwORBAEAAAAOABYAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAYAAAAAAAAAAAACAAAAAAIAAAMAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABkAGQANAiaCx4AHgAeAB4ACQAAAAAAAAAAAAAA//8AAAAAAAAAAB4AHgABAAAAAwDgAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAQAAgAAAAAAAAAAAAEAMgAyANT+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYACoAAAAgAAEAAAAgAAAAQAAAAAYAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs/wAAAAAAAAAAAABCAAAAAQAAALAAAAAAAAAAAAAAAAAAAAAeAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBARIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmYMAFBSSU5URVJfTkFNRRwARVBTT042RkM5OUMgKFdQLTQwMjUgU2VyaWVzKQsARFJJVkVSX05BTUUUAEVQU09OIFdQLTQwMjUgU2VyaWVz + false + false + false + $(inst)/share/palette%3B$(user)/config/standard.sob + false + 0 + 0 + true + false + false + true + false + true + 0 + $(inst)/share/palette%3B$(user)/config/standard.soc + $(inst)/share/palette%3B$(user)/config/standard.sod + $(inst)/share/palette%3B$(user)/config/standard.soe + $(inst)/share/palette%3B$(user)/config/standard.soh + $(inst)/share/palette%3B$(user)/config/standard.sog + true + 4 + false + false + true + low-resolution + false + false + false + true + false + true + true + 7 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xmloff/qa/unit/data/textbox-loss.docx b/xmloff/qa/unit/data/textbox-loss.docx new file mode 100644 index 0000000000..9190e662f8 Binary files /dev/null and b/xmloff/qa/unit/data/textbox-loss.docx differ diff --git a/xmloff/qa/unit/data/theme.fodp b/xmloff/qa/unit/data/theme.fodp new file mode 100644 index 0000000000..dd64602818 --- /dev/null +++ b/xmloff/qa/unit/data/theme.fodp @@ -0,0 +1,997 @@ + + + + PowerPoint Presentationvmiklosvmiklos12021-11-22T13:38:232021-11-22T13:38:35P0DLibreOfficeDev/7.6.0.0.alpha1$Linux_X86_64 LibreOffice_project/e2dcf766684ce986dd5a68ddabc34d75374e13ba16.0000Widescreen1 + + + 0 + 0 + 14099 + 9999 + + + view1 + false + false + true + true + true + true + false + false + true + 1500 + false + Hw== + Hw== + + false + true + true + 0 + 0 + false + true + true + 4 + 0 + -1710 + -508 + 34958 + 22504 + 2000 + 2000 + 500 + 500 + 2000 + 4 + 2000 + 4 + false + 1500 + true + false + false + true + true + + + + + 6 + false + false + false + false + false + 0 + false + false + true + true + true + true + false + true + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.soe + true + true + + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.sog + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.sob + 2540 + + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.soc + 4 + true + 0 + false + 0 + false + false + low-resolution + true + false + false + true + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.sod + false + false + true + $(brandbaseurl)/share/palette%3B$(userpath)/config/standard.soh + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <number> + + + + + + + + + + + + + + + + + + + + + + + Click to edit Master title style + + + + + + + + + + + + + + + <number> + + + + + + + + + + + + + + + + + + + + + + + + + <number> + + + + + + + + + + Blue, Accent 1, Lighter 40% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xmloff/qa/unit/data/video-snapshot.odp b/xmloff/qa/unit/data/video-snapshot.odp new file mode 100644 index 0000000000..ca3b7f21dc Binary files /dev/null and b/xmloff/qa/unit/data/video-snapshot.odp differ diff --git a/xmloff/qa/unit/draw.cxx b/xmloff/qa/unit/draw.cxx new file mode 100644 index 0000000000..8d89065d44 --- /dev/null +++ b/xmloff/qa/unit/draw.cxx @@ -0,0 +1,815 @@ +/* -*- 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 + +using namespace ::com::sun::star; + +/// Covers xmloff/source/draw/ fixes. +class XmloffDrawTest : public UnoApiXmlTest +{ +public: + XmloffDrawTest(); + uno::Reference getShape(sal_uInt8 nShapeIndex); + + uno::Reference + getShapeTextPortion(sal_uInt32 nIndex, uno::Reference const& xShape) + { + uno::Reference xPortion; + + uno::Reference xEnumAccess(xShape, uno::UNO_QUERY); + if (!xEnumAccess->hasElements()) + return xPortion; + uno::Reference xEnum(xEnumAccess->createEnumeration()); + uno::Reference xTextContent; + xEnum->nextElement() >>= xTextContent; + if (!xTextContent.is()) + return xPortion; + + uno::Reference xParaEnumAccess(xTextContent, uno::UNO_QUERY); + uno::Reference xParaEnum(xParaEnumAccess->createEnumeration()); + sal_uInt32 nCurrent = 0; + xPortion = uno::Reference(xParaEnum->nextElement(), uno::UNO_QUERY); + while (nIndex != nCurrent) + { + ++nCurrent; + xPortion + = uno::Reference(xParaEnum->nextElement(), uno::UNO_QUERY); + } + return xPortion; + } +}; + +XmloffDrawTest::XmloffDrawTest() + : UnoApiXmlTest("/xmloff/qa/unit/data/") +{ +} + +uno::Reference XmloffDrawTest::getShape(sal_uInt8 nShapeIndex) +{ + uno::Reference xDrawPagesSupplier(mxComponent, + uno::UNO_QUERY_THROW); + uno::Reference xDrawPages(xDrawPagesSupplier->getDrawPages()); + uno::Reference xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW); + uno::Reference xShape(xDrawPage->getByIndex(nShapeIndex), + uno::UNO_QUERY_THROW); + return xShape; +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTextBoxLoss) +{ + // Load a document that has a shape with a textbox in it. Save it to ODF and reload. + loadFromFile(u"textbox-loss.docx"); + saveAndReload("impress8"); + + // Make sure that the shape is still a textbox. + uno::Reference xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); + uno::Reference xShape(xDrawPage->getByIndex(1), uno::UNO_QUERY); + bool bTextBox = false; + xShape->getPropertyValue("TextBox") >>= bTextBox; + + // Without the accompanying fix in place, this test would have failed, as the shape only had + // editeng text, losing the image part of the shape text. + CPPUNIT_ASSERT(bTextBox); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf141301_Extrusion_Angle) +{ + // Load a document that has a custom shape with extrusion direction as set by LO as its default. + loadFromFile(u"tdf141301_Extrusion_Skew.odg"); + + // Prepare use of XPath + save("draw8"); + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + + // Without fix draw:extrusion-skew="50 -135" was not written to file although "50 -135" is not + // default in ODF, but only default inside LO. + assertXPath(pXmlDoc, "//draw:enhanced-geometry"_ostr, "extrusion-skew"_ostr, "50 -135"); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testThemeExport) +{ + // Create an Impress document which has a master page which has a theme associated with it. + mxComponent = loadFromDesktop("private:factory/simpress"); + uno::Reference xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPage( + xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference xMasterPage(xDrawPage->getMasterPage(), uno::UNO_QUERY); + + auto pTheme = std::make_shared("mytheme"); + auto pColorSet = std::make_shared("mycolorscheme"); + pColorSet->add(model::ThemeColorType::Dark1, 0x0); + pColorSet->add(model::ThemeColorType::Light1, 0x1); + pColorSet->add(model::ThemeColorType::Dark2, 0x2); + pColorSet->add(model::ThemeColorType::Light2, 0x3); + pColorSet->add(model::ThemeColorType::Accent1, 0x4); + pColorSet->add(model::ThemeColorType::Accent2, 0x5); + pColorSet->add(model::ThemeColorType::Accent3, 0x6); + pColorSet->add(model::ThemeColorType::Accent4, 0x7); + pColorSet->add(model::ThemeColorType::Accent5, 0x8); + pColorSet->add(model::ThemeColorType::Accent6, 0x9); + pColorSet->add(model::ThemeColorType::Hyperlink, 0xa); + pColorSet->add(model::ThemeColorType::FollowedHyperlink, 0xb); + pTheme->setColorSet(pColorSet); + + uno::Reference xTheme = model::theme::createXTheme(pTheme); + xMasterPage->setPropertyValue("Theme", uno::Any(xTheme)); + + // Export to ODP: + save("impress8"); + + // Check if the 12 colors are written in the XML: + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 12 + // - Actual : 0 + // - XPath '//style:master-page/loext:theme/loext:color-table/loext:color' number of nodes is incorrect + // i.e. the theme was lost on exporting to ODF. + assertXPath(pXmlDoc, "//style:master-page/loext:theme/loext:theme-colors/loext:color"_ostr, 12); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testVideoSnapshot) +{ + // Execute ODP import: + loadFromFile(u"video-snapshot.odp"); + uno::Reference xDrawPagesSupplier(mxComponent, + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT(xDrawPagesSupplier.is()); + uno::Reference xDrawPages(xDrawPagesSupplier->getDrawPages()); + uno::Reference xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT(xDrawPage.is()); + auto pUnoPage = dynamic_cast(xDrawPage.get()); + SdrPage* pSdrPage = pUnoPage->GetSdrPage(); + auto pMedia = dynamic_cast(pSdrPage->GetObj(0)); + + // Check that the preview was imported: + const avmedia::MediaItem& rItem = pMedia->getMediaProperties(); + const Graphic& rGraphic = rItem.getGraphic(); + CPPUNIT_ASSERT(!rGraphic.IsNone()); + + // Check that the crop was imported: + const text::GraphicCrop& rCrop = rItem.getCrop(); + CPPUNIT_ASSERT_EQUAL(static_cast(0), rCrop.Top); + CPPUNIT_ASSERT_EQUAL(static_cast(0), rCrop.Bottom); + CPPUNIT_ASSERT_EQUAL(static_cast(1356), rCrop.Left); + CPPUNIT_ASSERT_EQUAL(static_cast(1356), rCrop.Right); + + // Execute ODP export: + save("impress8"); + + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Check that the preview was exported: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // - XPath '//draw:frame[@draw:style-name='gr1']/draw:image' number of nodes is incorrect + // i.e. the preview wasn't exported to ODP. + assertXPath(pXmlDoc, "//draw:frame[@draw:style-name='gr1']/draw:image"_ostr, "href"_ostr, + "Pictures/MediaPreview1.png"); + // Check that the crop was exported: + assertXPath(pXmlDoc, "//style:style[@style:name='gr1']/style:graphic-properties"_ostr, + "clip"_ostr, "rect(0cm, 1.356cm, 0cm, 1.356cm)"); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testThemeImport) +{ + // Given a document that has a master page with a theme associated: + loadFromFile(u"theme.fodp"); + + // Then make sure the doc model has a master page with a theme: + uno::Reference xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPage( + xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference xMasterpage(xDrawPage->getMasterPage(), uno::UNO_QUERY); + + uno::Reference xTheme; + xMasterpage->getPropertyValue("Theme") >>= xTheme; + + // We expect the theme to be set on the master page + CPPUNIT_ASSERT(xTheme.is()); + auto* pUnoTheme = dynamic_cast(xTheme.get()); + CPPUNIT_ASSERT(pUnoTheme); + auto pTheme = pUnoTheme->getTheme(); + CPPUNIT_ASSERT(pTheme); + + CPPUNIT_ASSERT_EQUAL(OUString("Office Theme"), pTheme->GetName()); + auto pColorSet = pTheme->getColorSet(); + CPPUNIT_ASSERT(pColorSet); + CPPUNIT_ASSERT_EQUAL(OUString("Office"), pColorSet->getName()); + + CPPUNIT_ASSERT_EQUAL(Color(0x954F72), + pColorSet->getColor(model::ThemeColorType::FollowedHyperlink)); +} + +namespace +{ +void checkFillAndLineComplexColors(uno::Reference const& xShape) +{ + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + { + uno::Reference xComplexColor; + xShapeProperties->getPropertyValue("FillComplexColor") >>= xComplexColor; + CPPUNIT_ASSERT(xComplexColor.is()); + auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); + CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3, aComplexColor.getThemeColorType()); + CPPUNIT_ASSERT_EQUAL(size_t(2), aComplexColor.getTransformations().size()); + auto const& rTrans1 = aComplexColor.getTransformations()[0]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTrans1.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(4000), rTrans1.mnValue); + auto const& rTrans2 = aComplexColor.getTransformations()[1]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff, rTrans2.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(6000), rTrans2.mnValue); + } + { + uno::Reference xComplexColor; + xShapeProperties->getPropertyValue("LineComplexColor") >>= xComplexColor; + CPPUNIT_ASSERT(xComplexColor.is()); + auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); + CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3, aComplexColor.getThemeColorType()); + CPPUNIT_ASSERT_EQUAL(size_t(2), aComplexColor.getTransformations().size()); + auto const& rTrans1 = aComplexColor.getTransformations()[0]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTrans1.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(6000), rTrans1.mnValue); + auto const& rTrans2 = aComplexColor.getTransformations()[1]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff, rTrans2.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(4000), rTrans2.mnValue); + } +} + +} // end anonymous ns + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testFillAndLineThemeColorExportImport) +{ + loadFromFile(u"FillAndStrokeThemeColorTest.fodp"); + + checkFillAndLineComplexColors(getShape(0)); + + save("impress8"); + + load(maTempFile.GetURL()); + + checkFillAndLineComplexColors(getShape(0)); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTextAndFillThemeColorExportImport) +{ + // Given a document that refers to a theme color: + loadFromFile(u"Reference-ThemeColors-TextAndFill.pptx"); + save("impress8"); + + // Make sure the export result has the theme reference: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + + // Text color + OString aStyle1( + "//style:style[@style:name='T2']/style:text-properties/loext:char-complex-color"_ostr); + assertXPath(pXmlDoc, aStyle1, "color-type"_ostr, "theme"); + assertXPath(pXmlDoc, aStyle1, "theme-type"_ostr, "accent3"); + assertXPath(pXmlDoc, aStyle1 + "/loext:transformation[1]", "type"_ostr, "lummod"); + assertXPath(pXmlDoc, aStyle1 + "/loext:transformation[1]", "value"_ostr, "2000"); + assertXPath(pXmlDoc, aStyle1 + "/loext:transformation[2]", "type"_ostr, "lumoff"); + assertXPath(pXmlDoc, aStyle1 + "/loext:transformation[2]", "value"_ostr, "8000"); + + OString aStyle2( + "//style:style[@style:name='T3']/style:text-properties/loext:char-complex-color"_ostr); + assertXPath(pXmlDoc, aStyle1, "color-type"_ostr, "theme"); + assertXPath(pXmlDoc, aStyle2, "theme-type"_ostr, "accent3"); + assertXPath(pXmlDoc, aStyle2 + "/loext:transformation[1]", "type"_ostr, "lummod"); + assertXPath(pXmlDoc, aStyle2 + "/loext:transformation[1]", "value"_ostr, "6000"); + assertXPath(pXmlDoc, aStyle2 + "/loext:transformation[2]", "type"_ostr, "lumoff"); + assertXPath(pXmlDoc, aStyle2 + "/loext:transformation[2]", "value"_ostr, "4000"); + + OString aStyle3( + "//style:style[@style:name='T4']/style:text-properties/loext:char-complex-color"_ostr); + assertXPath(pXmlDoc, aStyle1, "color-type"_ostr, "theme"); + assertXPath(pXmlDoc, aStyle3, "theme-type"_ostr, "accent3"); + assertXPath(pXmlDoc, aStyle3 + "/loext:transformation[1]", "type"_ostr, "lummod"); + assertXPath(pXmlDoc, aStyle3 + "/loext:transformation[1]", "value"_ostr, "5000"); + + // Shapes fill color + OString aShape1("//style:style[@style:name='gr1']/style:graphic-properties/" + "loext:fill-complex-color"_ostr); + assertXPath(pXmlDoc, aStyle1, "color-type"_ostr, "theme"); + assertXPath(pXmlDoc, aShape1, "theme-type"_ostr, "accent2"); + assertXPath(pXmlDoc, aShape1 + "/loext:transformation[1]", "type"_ostr, "lummod"); + assertXPath(pXmlDoc, aShape1 + "/loext:transformation[1]", "value"_ostr, "2000"); + assertXPath(pXmlDoc, aShape1 + "/loext:transformation[2]", "type"_ostr, "lumoff"); + assertXPath(pXmlDoc, aShape1 + "/loext:transformation[2]", "value"_ostr, "8000"); + + OString aShape2("//style:style[@style:name='gr2']/style:graphic-properties/" + "loext:fill-complex-color"_ostr); + assertXPath(pXmlDoc, aStyle1, "color-type"_ostr, "theme"); + assertXPath(pXmlDoc, aShape2, "theme-type"_ostr, "accent2"); + assertXPath(pXmlDoc, aShape2 + "/loext:transformation[1]", "type"_ostr, "lummod"); + assertXPath(pXmlDoc, aShape2 + "/loext:transformation[1]", "value"_ostr, "6000"); + assertXPath(pXmlDoc, aShape2 + "/loext:transformation[2]", "type"_ostr, "lumoff"); + assertXPath(pXmlDoc, aShape2 + "/loext:transformation[2]", "value"_ostr, "4000"); + + OString aShape3("//style:style[@style:name='gr3']/style:graphic-properties/" + "loext:fill-complex-color"_ostr); + assertXPath(pXmlDoc, aStyle1, "color-type"_ostr, "theme"); + assertXPath(pXmlDoc, aShape3, "theme-type"_ostr, "accent2"); + assertXPath(pXmlDoc, aShape3 + "/loext:transformation[1]", "type"_ostr, "lummod"); + assertXPath(pXmlDoc, aShape3 + "/loext:transformation[1]", "value"_ostr, "5000"); + + // reload + load(maTempFile.GetURL()); + + // check fill color theme + { + uno::Reference xShape(getShape(0)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + uno::Reference xComplexColor; + xShapeProperties->getPropertyValue("FillComplexColor") >>= xComplexColor; + CPPUNIT_ASSERT(xComplexColor.is()); + auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); + CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent2, aComplexColor.getThemeColorType()); + CPPUNIT_ASSERT_EQUAL(size_t(2), aComplexColor.getTransformations().size()); + auto const& rTrans1 = aComplexColor.getTransformations()[0]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTrans1.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(2000), rTrans1.mnValue); + auto const& rTrans2 = aComplexColor.getTransformations()[1]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff, rTrans2.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(8000), rTrans2.mnValue); + } + { + uno::Reference xShape(getShape(1)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + uno::Reference xComplexColor; + xShapeProperties->getPropertyValue("FillComplexColor") >>= xComplexColor; + CPPUNIT_ASSERT(xComplexColor.is()); + auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); + CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent2, aComplexColor.getThemeColorType()); + CPPUNIT_ASSERT_EQUAL(size_t(2), aComplexColor.getTransformations().size()); + auto const& rTrans1 = aComplexColor.getTransformations()[0]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTrans1.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(6000), rTrans1.mnValue); + auto const& rTrans2 = aComplexColor.getTransformations()[1]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff, rTrans2.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(4000), rTrans2.mnValue); + } + { + uno::Reference xShape(getShape(2)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + uno::Reference xComplexColor; + xShapeProperties->getPropertyValue("FillComplexColor") >>= xComplexColor; + CPPUNIT_ASSERT(xComplexColor.is()); + auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); + CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent2, aComplexColor.getThemeColorType()); + CPPUNIT_ASSERT_EQUAL(size_t(1), aComplexColor.getTransformations().size()); + auto const& rTrans1 = aComplexColor.getTransformations()[0]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTrans1.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(5000), rTrans1.mnValue); + } + + // Char color theme + // Shape 4 + { + // Check the first text portion properties + uno::Reference xShape(getShape(3)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xPortion = getShapeTextPortion(0, xShape); + CPPUNIT_ASSERT(xPortion.is()); + uno::Reference xComplexColor; + xPortion->getPropertyValue("CharComplexColor") >>= xComplexColor; + CPPUNIT_ASSERT(xComplexColor.is()); + auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); + CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3, aComplexColor.getThemeColorType()); + auto const& rTransforms = aComplexColor.getTransformations(); + CPPUNIT_ASSERT_EQUAL(size_t(2), rTransforms.size()); + auto const& rTrans1 = rTransforms[0]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTrans1.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(2000), rTrans1.mnValue); + auto const& rTrans2 = rTransforms[1]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff, rTrans2.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(8000), rTrans2.mnValue); + } + // Shape 5 + { + // Check the first text portion properties + uno::Reference xShape(getShape(4)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xPortion = getShapeTextPortion(0, xShape); + CPPUNIT_ASSERT(xPortion.is()); + uno::Reference xComplexColor; + xPortion->getPropertyValue("CharComplexColor") >>= xComplexColor; + CPPUNIT_ASSERT(xComplexColor.is()); + auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); + CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3, aComplexColor.getThemeColorType()); + auto const& rTransforms = aComplexColor.getTransformations(); + CPPUNIT_ASSERT_EQUAL(size_t(2), rTransforms.size()); + auto const& rTrans1 = rTransforms[0]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTrans1.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(6000), rTrans1.mnValue); + auto const& rTrans2 = rTransforms[1]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff, rTrans2.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(4000), rTrans2.mnValue); + } + // Shape 6 + { + // Check the first text portion properties + uno::Reference xShape(getShape(5)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xPortion = getShapeTextPortion(0, xShape); + CPPUNIT_ASSERT(xPortion.is()); + uno::Reference xComplexColor; + xPortion->getPropertyValue("CharComplexColor") >>= xComplexColor; + CPPUNIT_ASSERT(xComplexColor.is()); + auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); + CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3, aComplexColor.getThemeColorType()); + CPPUNIT_ASSERT_EQUAL(size_t(1), aComplexColor.getTransformations().size()); + auto const& rTrans1 = aComplexColor.getTransformations()[0]; + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTrans1.meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(5000), rTrans1.mnValue); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testThemeColor_ShapeFill) +{ + loadFromFile(u"ReferenceShapeFill.pptx"); + save("impress8"); + // reload + load(maTempFile.GetURL()); + + // check fill color theme + uno::Reference xShape(getShape(0)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + uno::Reference xComplexColor; + xShapeProperties->getPropertyValue("FillComplexColor") >>= xComplexColor; + CPPUNIT_ASSERT(xComplexColor.is()); + auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); + CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent6, aComplexColor.getThemeColorType()); + CPPUNIT_ASSERT_EQUAL(size_t(1), aComplexColor.getTransformations().size()); + CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, + aComplexColor.getTransformations()[0].meType); + CPPUNIT_ASSERT_EQUAL(sal_Int16(7500), aComplexColor.getTransformations()[0].mnValue); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTableInShape) +{ + // Given a document with a shape with a "FrameX" parent style (starts with Frame, but is not + // Frame): + loadFromFile(u"table-in-shape.fodt"); + + // Then make sure the table inside the shape is not lost: + uno::Reference xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); + uno::Reference xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference xText(xShape->getText(), uno::UNO_QUERY); + uno::Reference xEnum = xText->createEnumeration(); + uno::Reference xTable(xEnum->nextElement(), uno::UNO_QUERY); + // Without the accompanying fix in place, this test would have crashed, as xTable was an empty + // reference, i.e. the table inside the shape was lost. + uno::Reference xCell(xTable->getCellByName("A1"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("A1"), xCell->getString()); +} + +// Tests for save/load of new (LO 7.4) attribute loext:extrusion-metal-type +namespace +{ +void lcl_assertMetalProperties(std::string_view sInfo, uno::Reference& rxShape) +{ + uno::Reference xShapeProps(rxShape, uno::UNO_QUERY); + uno::Sequence aGeoPropSeq; + xShapeProps->getPropertyValue("CustomShapeGeometry") >>= aGeoPropSeq; + comphelper::SequenceAsHashMap aGeoPropMap(aGeoPropSeq); + uno::Sequence aExtrusionSeq; + aGeoPropMap.getValue("Extrusion") >>= aExtrusionSeq; + comphelper::SequenceAsHashMap aExtrusionPropMap(aExtrusionSeq); + + bool bIsMetal(false); + aExtrusionPropMap.getValue("Metal") >>= bIsMetal; + OString sMsg = OString::Concat(sInfo) + " Metal"; + CPPUNIT_ASSERT_MESSAGE(sMsg.getStr(), bIsMetal); + + sal_Int16 nMetalType(-1); + aExtrusionPropMap.getValue("MetalType") >>= nMetalType; + sMsg = OString::Concat(sInfo) + " MetalType"; + CPPUNIT_ASSERT_EQUAL_MESSAGE( + sMsg.getStr(), css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible, nMetalType); +} +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testExtrusionMetalTypeExtended) +{ + loadFromFile(u"tdf145700_3D_metal_type_MSCompatible.doc"); + // verify properties + uno::Reference xShape(getShape(0)); + lcl_assertMetalProperties("from doc", xShape); + + // Test, that new attribute is written with loext namespace. Adapt when attribute is added to ODF. + save("writer8"); + + // assert XML. + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath(pXmlDoc, "//draw:enhanced-geometry"_ostr, "extrusion-metal"_ostr, "true"); + assertXPath( + pXmlDoc, + "//draw:enhanced-geometry[@loext:extrusion-metal-type='loext:MetalMSCompatible']"_ostr); + + // reload + mxComponent = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument"); + // verify properties + uno::Reference xShapeReload(getShape(0)); + lcl_assertMetalProperties("from ODF 1.3 extended", xShapeReload); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testExtrusionMetalTypeStrict) +{ + loadFromFile(u"tdf145700_3D_metal_type_MSCompatible.doc"); + + // save ODF 1.3 strict and test, that new attribute is not written. Adapt when attribute is + // added to ODF. + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion(GetODFDefaultVersion()); + SetODFDefaultVersion(SvtSaveOptions::ODFVER_013); + save("writer8"); + + // assert XML. + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath(pXmlDoc, "//draw:enhanced-geometry"_ostr, "extrusion-metal"_ostr, "true"); + assertXPath(pXmlDoc, "//draw:enhanced-geometry[@loext:extrusion-metal-type]"_ostr, 0); + + SetODFDefaultVersion(nCurrentODFVersion); +} + +namespace +{ +void lcl_assertSpecularityProperty(std::string_view sInfo, uno::Reference& rxShape) +{ + uno::Reference xShapeProps(rxShape, uno::UNO_QUERY); + uno::Sequence aGeoPropSeq; + xShapeProps->getPropertyValue("CustomShapeGeometry") >>= aGeoPropSeq; + comphelper::SequenceAsHashMap aGeoPropMap(aGeoPropSeq); + uno::Sequence aExtrusionSeq; + aGeoPropMap.getValue("Extrusion") >>= aExtrusionSeq; + comphelper::SequenceAsHashMap aExtrusionPropMap(aExtrusionSeq); + + double fSpecularity(-1.0); + aExtrusionPropMap.getValue("Specularity") >>= fSpecularity; + OString sMsg = OString::Concat(sInfo) + "Specularity"; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sMsg.getStr(), 122.0703125, fSpecularity); +} +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testExtrusionSpecularityExtended) +{ + loadFromFile(u"tdf147580_extrusion-specularity.doc"); + // verify property + uno::Reference xShape(getShape(0)); + lcl_assertSpecularityProperty("from doc", xShape); + + // Test, that attribute is written in draw namespace with value 100% and in loext namespace with + // value 122.0703125%. + save("writer8"); + + // assert XML. + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath(pXmlDoc, "//draw:enhanced-geometry[@draw:extrusion-specularity='100%']"_ostr); + assertXPath(pXmlDoc, + "//draw:enhanced-geometry[@loext:extrusion-specularity-loext='122.0703125%']"_ostr); + + // reload and verify, that the loext value is used + mxComponent = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument"); + // verify properties + uno::Reference xShapeReload(getShape(0)); + lcl_assertSpecularityProperty("from ODF 1.3 extended", xShapeReload); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testExtrusionSpecularity) +{ + loadFromFile(u"tdf147580_extrusion-specularity.doc"); + + // The file has c3DSpecularAmt="80000" which results internally in specularity=122%. + // Save to ODF 1.3 strict and make sure it does not produce a validation error. + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion(GetODFDefaultVersion()); + SetODFDefaultVersion(SvtSaveOptions::ODFVER_013); + save("writer8"); + + SetODFDefaultVersion(nCurrentODFVersion); +} + +namespace +{ +bool lcl_getShapeSegments(uno::Sequence& rSegments, + const uno::Reference& xShape) +{ + uno::Reference xShapeProps(xShape, uno::UNO_QUERY_THROW); + uno::Any anotherAny = xShapeProps->getPropertyValue("CustomShapeGeometry"); + uno::Sequence aCustomShapeGeometry; + if (!(anotherAny >>= aCustomShapeGeometry)) + return false; + uno::Sequence aPathProps; + for (beans::PropertyValue const& rProp : std::as_const(aCustomShapeGeometry)) + { + if (rProp.Name == "Path") + { + rProp.Value >>= aPathProps; + break; + } + } + + for (beans::PropertyValue const& rProp : std::as_const(aPathProps)) + { + if (rProp.Name == "Segments") + { + rProp.Value >>= rSegments; + break; + } + } + if (rSegments.getLength() > 2) + return true; + else + return false; +} +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf148714_CurvedArrowsOld) +{ + // Load a document with CurveArrow shapes with faulty path as written by older LO versions. + loadFromFile(u"tdf148714_CurvedArrowsOld.odp"); + + // Make sure, that the error has been corrected on opening. + for (sal_Int32 nShapeIndex = 0; nShapeIndex < 4; nShapeIndex++) + { + uno::Reference xShape(getShape(nShapeIndex)); + uno::Sequence aSegments; + CPPUNIT_ASSERT(lcl_getShapeSegments(aSegments, xShape)); + + if (nShapeIndex == 0 || nShapeIndex == 3) + { + // curvedDownArrow or curvedLeftArrow. Segments should start with VW. Without fix it was + // V with count 2, which means VV. + CPPUNIT_ASSERT_EQUAL( + sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC), + aSegments[0].Command); + CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments[0].Count); + CPPUNIT_ASSERT_EQUAL( + sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO), + aSegments[1].Command); + CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments[1].Count); + } + else + { + // curvedUpArrow or curvedRightArrow. Segments should start with BA. Without fix is was + // B with count 2, which means BB. + CPPUNIT_ASSERT_EQUAL(sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::ARC), + aSegments[0].Command); + CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments[0].Count); + CPPUNIT_ASSERT_EQUAL(sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::ARCTO), + aSegments[1].Command); + CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments[1].Count); + } + } +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTextRotationPlusPre) +{ + loadFromFile(u"tdf149551_verticalText.pptx"); + // The file has a shape with attribute vert="vert" in element. That generates a + // TextPreRotateAngle attribute in CustomShapeGeometry. + + // Add a TextRotateAngle attribute. + uno::Reference xShape(getShape(0)); + uno::Reference xShapeProps(xShape, uno::UNO_QUERY); + uno::Sequence aGeomSeq; + xShapeProps->getPropertyValue("CustomShapeGeometry") >>= aGeomSeq; + auto aGeomVec(comphelper::sequenceToContainer>(aGeomSeq)); + aGeomVec.push_back(comphelper::makePropertyValue("TextRotateAngle", sal_Int32(45))); + aGeomSeq = comphelper::containerToSequence(aGeomVec); + xShapeProps->setPropertyValue("CustomShapeGeometry", uno::Any(aGeomSeq)); + + // Save to ODF. Without the fix, a file format error was produced, because attribute + // draw:text-rotate-angle was written twice, one from TextPreRotateAngle and the other from + // TextRotateAngle. + // This should already catch the format error, but does not, see tdf#149567 + // But reload catches it. + saveAndReload("writer8"); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf156975_ThemeExport) +{ + // It tests, that a theme is written to master page in Draw documents. + // Without fix for tdf#156975 it was not written at all. + // The test needs to be adapted, when themes are available in ODF. + + mxComponent = loadFromDesktop("private:factory/sdraw"); + // generate a theme to be sure we have got one and know the values + uno::Reference xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPage( + xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference xMasterPageProps(xDrawPage->getMasterPage(), + uno::UNO_QUERY); + + auto pTheme = std::make_shared("Custom"); + auto pColorSet = std::make_shared("My Colors"); + pColorSet->add(model::ThemeColorType::Dark1, 0x000000); + pColorSet->add(model::ThemeColorType::Light1, 0xffff11); + pColorSet->add(model::ThemeColorType::Dark2, 0x002200); + pColorSet->add(model::ThemeColorType::Light2, 0xff33ff); + pColorSet->add(model::ThemeColorType::Accent1, 0x440000); + pColorSet->add(model::ThemeColorType::Accent2, 0x005500); + pColorSet->add(model::ThemeColorType::Accent3, 0x000066); + pColorSet->add(model::ThemeColorType::Accent4, 0x777700); + pColorSet->add(model::ThemeColorType::Accent5, 0x880088); + pColorSet->add(model::ThemeColorType::Accent6, 0x009999); + pColorSet->add(model::ThemeColorType::Hyperlink, 0x0a0a0a); + pColorSet->add(model::ThemeColorType::FollowedHyperlink, 0xb0b0b0); + pTheme->setColorSet(pColorSet); + + uno::Reference xTheme = model::theme::createXTheme(pTheme); + xMasterPageProps->setPropertyValue("Theme", uno::Any(xTheme)); + + // save as odg + save("draw8"); + + // and check the markup. + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + static constexpr OString sThemePath + = "//office:master-styles/style:master-page/loext:theme"_ostr; + assertXPath(pXmlDoc, sThemePath, 1); + assertXPath(pXmlDoc, sThemePath + "[@loext:name='Custom']"); + + const OString sThemeColorsPath = sThemePath + "/loext:theme-colors"; + assertXPath(pXmlDoc, sThemeColorsPath, 1); + assertXPath(pXmlDoc, sThemeColorsPath + "[@loext:name='My Colors']"); + + const OString sThemeColorPath = sThemeColorsPath + "/loext:color"; + assertXPath(pXmlDoc, sThemeColorPath, 12); + assertXPath(pXmlDoc, sThemeColorPath + "[3]", "name"_ostr, "dark2"); + assertXPath(pXmlDoc, sThemeColorPath + "[3]", "color"_ostr, "#002200"); + assertXPath(pXmlDoc, sThemeColorPath + "[9]", "name"_ostr, "accent5"); + assertXPath(pXmlDoc, sThemeColorPath + "[9]", "color"_ostr, "#880088"); + assertXPath(pXmlDoc, sThemeColorPath + "[12]", "name"_ostr, "followed-hyperlink"); + assertXPath(pXmlDoc, sThemeColorPath + "[12]", "color"_ostr, "#b0b0b0"); +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf157018_ThemeImportDraw) +{ + // Similar to testThemeImport but for Draw. + // Load document with custom color theme + loadFromFile(u"tdf157018_CustomTheme.fodg"); + + // First make sure the doc model has a master page with a theme: + uno::Reference xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPage( + xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference xMasterpage(xDrawPage->getMasterPage(), uno::UNO_QUERY); + + uno::Reference xTheme; + xMasterpage->getPropertyValue("Theme") >>= xTheme; + CPPUNIT_ASSERT(xTheme.is()); + + // Then make sure it is the custom color theme + auto* pUnoTheme = dynamic_cast(xTheme.get()); + CPPUNIT_ASSERT(pUnoTheme); + auto pTheme = pUnoTheme->getTheme(); + CPPUNIT_ASSERT(pTheme); + + CPPUNIT_ASSERT_EQUAL(OUString("Custom"), pTheme->GetName()); + auto pColorSet = pTheme->getColorSet(); + CPPUNIT_ASSERT(pColorSet); + CPPUNIT_ASSERT_EQUAL(OUString("My Colors"), pColorSet->getName()); + + // and test some colors + CPPUNIT_ASSERT_EQUAL(Color(0xFFFF11), pColorSet->getColor(model::ThemeColorType::Light1)); + CPPUNIT_ASSERT_EQUAL(Color(0x0A0A0A), pColorSet->getColor(model::ThemeColorType::Hyperlink)); + CPPUNIT_ASSERT_EQUAL(Color(0x440000), pColorSet->getColor(model::ThemeColorType::Accent1)); +} +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/qa/unit/style.cxx b/xmloff/qa/unit/style.cxx new file mode 100644 index 0000000000..178b0f2161 --- /dev/null +++ b/xmloff/qa/unit/style.cxx @@ -0,0 +1,663 @@ +/* -*- 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 + +using namespace ::com::sun::star; + +/// Covers xmloff/source/style/ fixes. +class XmloffStyleTest : public UnoApiXmlTest +{ +public: + XmloffStyleTest(); + uno::Reference getShape(sal_uInt8 nShapeIndex); +}; + +XmloffStyleTest::XmloffStyleTest() + : UnoApiXmlTest("/xmloff/qa/unit/data/") +{ +} + +uno::Reference XmloffStyleTest::getShape(sal_uInt8 nShapeIndex) +{ + uno::Reference xDrawPagesSupplier(mxComponent, + uno::UNO_QUERY_THROW); + uno::Reference xDrawPages(xDrawPagesSupplier->getDrawPages()); + uno::Reference xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW); + uno::Reference xShape(xDrawPage->getByIndex(nShapeIndex), + uno::UNO_QUERY_THROW); + return xShape; +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testFillImageBase64) +{ + // Load a flat ODG that has base64-encoded bitmap as a fill style. + loadFromFile(u"fill-image-base64.fodg"); + uno::Reference xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference xBitmaps( + xFactory->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY); + + // Without the accompanying fix in place, this test would have failed, as the base64 stream was + // not considered when parsing the fill-image style. + CPPUNIT_ASSERT(xBitmaps->hasByName("libreoffice_0")); +} + +namespace +{ +struct XmlFont +{ + OString aName; + OString aFontFamilyGeneric; + bool operator<(const XmlFont& rOther) const + { + sal_Int32 nRet = aName.compareTo(rOther.aName); + if (nRet != 0) + { + return nRet < 0; + } + + return aFontFamilyGeneric.compareTo(rOther.aFontFamilyGeneric) < 0; + } +}; + +Color asColor(com::sun::star::rendering::RGBColor const& rRGBColor) +{ + basegfx::BColor aBColor(rRGBColor.Red, rRGBColor.Green, rRGBColor.Blue); + return Color(aBColor); +} +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testFontSorting) +{ + // Given an empty document with default fonts (Liberation Sans, Lucida Sans, etc): + mxComponent = loadFromDesktop("private:factory/swriter"); + + // When saving that document to ODT: + save("writer8"); + + // Then make sure elements are sorted (by style:name="..."): + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + xmlXPathObjectPtr pXPath = getXPathNode( + pXmlDoc, "/office:document-content/office:font-face-decls/style:font-face"_ostr); + xmlNodeSetPtr pXmlNodes = pXPath->nodesetval; + int nNodeCount = xmlXPathNodeSetGetLength(pXmlNodes); + std::vector aXMLFonts; + std::vector aSortedFonts; + for (int i = 0; i < nNodeCount; ++i) + { + xmlNodePtr pXmlNode = pXmlNodes->nodeTab[i]; + xmlChar* pName = xmlGetProp(pXmlNode, BAD_CAST("name")); + OString aName(reinterpret_cast(pName)); + + // Ignore numbers at the end, those are just appended to make all names unique. + while (rtl::isAsciiDigit(static_cast(aName[aName.getLength() - 1]))) + { + aName = aName.copy(0, aName.getLength() - 1); + } + + xmlChar* pFontFamilyGeneric = xmlGetProp(pXmlNode, BAD_CAST("font-family-generic")); + OString aFontFamilyGeneric; + if (pFontFamilyGeneric) + { + aFontFamilyGeneric = OString(reinterpret_cast(pFontFamilyGeneric)); + } + + aXMLFonts.push_back(XmlFont{ aName, aFontFamilyGeneric }); + aSortedFonts.push_back(XmlFont{ aName, aFontFamilyGeneric }); + xmlFree(pName); + } + std::sort(aSortedFonts.begin(), aSortedFonts.end()); + size_t nIndex = 0; + for (const auto& rFont : aSortedFonts) + { + // Without the accompanying fix in place, this test would have failed with: + // - Expected: Liberation Sans + // - Actual : Lucida Sans1 + // i.e. the output was not lexicographically sorted, "u" was before "i". + CPPUNIT_ASSERT_EQUAL(rFont.aName, aXMLFonts[nIndex].aName); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: swiss + // - Actual : system + // i.e. the output was not lexicographically sorted when style:name was the same, but + // style:font-family-generic was not the same. + CPPUNIT_ASSERT_EQUAL(rFont.aFontFamilyGeneric, aXMLFonts[nIndex].aFontFamilyGeneric); + ++nIndex; + } + xmlXPathFreeObject(pXPath); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testRtlGutter) +{ + // Given a document with a gutter margin and an RTL writing mode: + // When loading that document from ODF: + loadFromFile(u"rtl-gutter.fodt"); + + // Then make sure the page style's RtlGutter property is true. + uno::Reference xStyleFamiliesSupplier(mxComponent, + uno::UNO_QUERY); + uno::Reference xStyleFamilies + = xStyleFamiliesSupplier->getStyleFamilies(); + uno::Reference xStyleFamily(xStyleFamilies->getByName("PageStyles"), + uno::UNO_QUERY); + uno::Reference xStandard(xStyleFamily->getByName("Standard"), + uno::UNO_QUERY); + bool bRtlGutter{}; + xStandard->getPropertyValue("RtlGutter") >>= bRtlGutter; + // Without the accompanying fix in place, this test would have failed as + // 's style:writing-mode="..." did not affect RtlGutter. + CPPUNIT_ASSERT(bRtlGutter); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testWritingModeBTLR) +{ + // Load document. It has a frame style with writing-mode bt-lr. + // In ODF 1.3 extended it is written as loext:writing-mode="bt-lr". + // In ODF 1.3 strict, there must not be an attribute at all. + loadFromFile(u"tdf150407_WritingModeBTLR_style.odt"); + + Resetter _([]() { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + return pBatch->commit(); + }); + + // Save to ODF 1.3 extended. Adapt 3 (=ODFVER_LATEST) to a to be ODFVER_013_EXTENDED when + // attribute value "bt-lr" is included in ODF strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + pBatch->commit(); + save("writer8"); + + // With applied fix for tdf150407 still loext:writing-mode="bt-lr" has to be written. + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + assertXPath(pXmlDoc, + "/office:document-styles/office:styles/style:style[@style:name='FrameBTLR']/" + "style:graphic-properties[@loext:writing-mode]"_ostr); + assertXPath(pXmlDoc, + "/office:document-styles/office:styles/style:style[@style:name='FrameBTLR']/" + "style:graphic-properties"_ostr, + "writing-mode"_ostr, "bt-lr"); + } + + loadFromFile(u"tdf150407_WritingModeBTLR_style.odt"); + // Save to ODF 1.3 strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch); + pBatch->commit(); + save("writer8"); + + // Without the fix an faulty 'writing-mode="bt-lr"' attribute was written in productive build. + // A debug build fails assertion in SvXMLNamespaceMap::GetQNameByKey(). + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + assertXPathNoAttribute(pXmlDoc, + "/office:document-styles/office:styles/" + "style:style[@style:name='FrameBTLR']/style:graphic-properties"_ostr, + "writing-mode"_ostr); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testPosRelBottomMargin) +{ + // Load document. It has a frame position with vertical position relative to bottom margin. + // In ODF 1.3 extended it is written as loext:vertical-rel="page-content-bottom". + // In ODF 1.3 strict, there must not be an attribute at all. + loadFromFile(u"tdf150407_PosRelBottomMargin.docx"); + + Resetter _([]() { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + return pBatch->commit(); + }); + + // Save to ODF 1.3 extended. Adapt 3 (=ODFVER_LATEST) to a to be ODFVER_013_EXTENDED when + // attribute value "page-content-bottom" is included in ODF strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + pBatch->commit(); + save("writer8"); + + // With applied fix for tdf150407 still loext:vertical-rel="page-content-bottom" has to be + // written. + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath( + pXmlDoc, + "/office:document-content/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties[@loext:vertical-rel]"_ostr); + assertXPath( + pXmlDoc, + "/office:document-content/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties"_ostr, + "vertical-rel"_ostr, "page-content-bottom"); + } + + loadFromFile(u"tdf150407_PosRelBottomMargin.docx"); + // Save to ODF 1.3 strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch); + pBatch->commit(); + save("writer8"); + + // Without the fix an faulty 'vertical-rel="page-content-bottom"' attribute was written in + // productive build. A debug build fails assertion in SvXMLNamespaceMap::GetQNameByKey(). + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPathNoAttribute(pXmlDoc, + "/office:document-content/office:automatic-styles/" + "style:style[@style:name='gr1']/style:graphic-properties"_ostr, + "vertical-rel"_ostr); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testPosRelTopMargin) +{ + // Load document. It has a frame position with vertical position relative to top margin. + // In ODF 1.3 extended it is written as loext:vertical-rel="page-content-top". + // In ODF 1.3 strict, there must not be an attribute at all. + loadFromFile(u"tdf150407_PosRelTopMargin.docx"); + + Resetter _([]() { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + return pBatch->commit(); + }); + + // Save to ODF 1.3 extended. Adapt 3 (=ODFVER_LATEST) to a to be ODFVER_013_EXTENDED when + // attribute value "page-content-top" is included in ODF strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + pBatch->commit(); + save("writer8"); + + // With applied fix for tdf150407 still loext:vertical-rel="page-content-top has to be + // written. + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath( + pXmlDoc, + "/office:document-content/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties[@loext:vertical-rel]"_ostr); + assertXPath( + pXmlDoc, + "/office:document-content/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties"_ostr, + "vertical-rel"_ostr, "page-content-top"); + } + + loadFromFile(u"tdf150407_PosRelTopMargin.docx"); + // Save to ODF 1.3 strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch); + pBatch->commit(); + save("writer8"); + + // Without the fix an faulty 'vertical-rel="page-content-top"' attribute was written in + // productive build. A debug build fails assertion in SvXMLNamespaceMap::GetQNameByKey(). + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPathNoAttribute(pXmlDoc, + "/office:document-content/office:automatic-styles/" + "style:style[@style:name='gr1']/style:graphic-properties"_ostr, + "vertical-rel"_ostr); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testMCGR_OldToNew) +{ + // The file contains a shape with linear gradient fill from red #ff0000 to yellow #ffff00, + // named 'red2yellow' + loadFromFile(u"MCGR_OldToNew.odg"); + + // saveAndReload includes validation and must not fail with the new elements and attributes. + saveAndReload("draw8"); + + // Examine file markup + // For compatibility the file should still have the old attributes 'start-color' and 'end-color' + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath + = "/office:document-styles/office:styles/draw:gradient[@draw:name='red2yellow']"_ostr; + assertXPath(pXmlDoc, sPath, "start-color"_ostr, "#ff0000"); + assertXPath(pXmlDoc, sPath, "end-color"_ostr, "#ffff00"); + + // And it must have the new 'gradient-stop' elements. + // The prefix 'loext' needs to be adapted, when the element is available in ODF strict. + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "offset"_ostr, "0"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-type"_ostr, "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-value"_ostr, "#ff0000"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "offset"_ostr, "1"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-type"_ostr, "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-value"_ostr, "#ffff00"); + + // Examine reloaded file + uno::Reference xShape(getShape(0)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + + // The old properties need to be still available, as they might be used in macros. + OUString sGradientName; + xShapeProperties->getPropertyValue("FillGradientName") >>= sGradientName; + CPPUNIT_ASSERT_EQUAL(u"red2yellow"_ustr, sGradientName); + awt::Gradient2 aGradient; + xShapeProperties->getPropertyValue("FillGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xFF0000), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xFFFF00), aGradient.EndColor); + + // Test new properties + auto aColorStopSeq = aGradient.ColorStops; + { + awt::ColorStop aColorStop = aColorStopSeq[0]; + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(Color(0xff0000), asColor(aColorStop.StopColor)); + } + { + awt::ColorStop aColorStop = aColorStopSeq[1]; + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(Color(0xffff00), asColor(aColorStop.StopColor)); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testMCGR_OldToNew_opacity) +{ + // The file contains a shape with solid fill and a radial transparency gradient with start 90%, + // end 0%, border 20% and center at 50%|50%. There is only one draw:opacity element in file. + loadFromFile(u"MCGR_OldToNew_opacity.odg"); + + // saveAndReload includes validation and must not fail with the new elements and attributes. + saveAndReload("draw8"); + + // Examine file markup + // For compatibility the file should still have the old attributes. + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath = "/office:document-styles/office:styles/draw:opacity"_ostr; + assertXPath(pXmlDoc, sPath, "start"_ostr, "10%"); // UI 90% transparency + assertXPath(pXmlDoc, sPath, "end"_ostr, "100%"); // UI 0% transparency + assertXPath(pXmlDoc, sPath, "border"_ostr, "20%"); + assertXPath(pXmlDoc, sPath, "cx"_ostr, "50%"); + assertXPath(pXmlDoc, sPath, "cy"_ostr, "50%"); + assertXPath(pXmlDoc, sPath, "style"_ostr, "radial"); + + // And it must have the new 'opacity-stop' elements. + // The prefix 'loext' needs to be adapted, when the element is available in ODF strict. + OString sFirstStop = sPath + "/loext:opacity-stop[1]"; + assertXPath(pXmlDoc, sFirstStop, "offset"_ostr, "0"); + // Because of converting through color, the grade of opacity is not exact "0.1" + double fOpacity = getXPathContent(pXmlDoc, sFirstStop + "/@svg:stop-opacity").toDouble(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(0.1, fOpacity, 0.002); + + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[2]", "offset"_ostr, "1"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[2]", "stop-opacity"_ostr, "1"); + + // Examine reloaded file + uno::Reference xShape(getShape(0)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + + // The old properties need to be still available, as they might be used in macros. + awt::Gradient2 aGradient; + xShapeProperties->getPropertyValue("FillTransparenceGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xE5E5E5), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aGradient.EndColor); + CPPUNIT_ASSERT_EQUAL(sal_Int16(20), aGradient.Border); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.XOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.YOffset); + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_RADIAL, aGradient.Style); + + // Test new properties + auto aColorStopSeq = aGradient.ColorStops; + { + awt::ColorStop aColorStop = aColorStopSeq[0]; + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(Color(0xe5e5e5), asColor(aColorStop.StopColor)); + } + { + awt::ColorStop aColorStop = aColorStopSeq[1]; + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(Color(0x000000), asColor(aColorStop.StopColor)); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testMCGR_threeStops) +{ + // The file contains a shape with square gradient fill from red #ff0000 over teal #0099bb to + // yellow #ffff00, named 'threeStops'. It has 45deg rotation, center 0%|50%, border 10%. + loadFromFile(u"MCGR_threeStops.fodt"); + + // saveAndReload includes validation and must not fail with the new elements and attributes. + saveAndReload("draw8"); + + // Examine file markup + // For compatibility the file should still have the old attributes 'start-color' and 'end-color' + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath + = "/office:document-styles/office:styles/draw:gradient[@draw:name='threeStops']"_ostr; + assertXPath(pXmlDoc, sPath, "start-color"_ostr, "#ff0000"); + assertXPath(pXmlDoc, sPath, "end-color"_ostr, "#ffff00"); + assertXPath(pXmlDoc, sPath, "style"_ostr, "square"); + assertXPath(pXmlDoc, sPath, "cx"_ostr, "0%"); + assertXPath(pXmlDoc, sPath, "cy"_ostr, "50%"); + assertXPath(pXmlDoc, sPath, "angle"_ostr, "45deg"); + assertXPath(pXmlDoc, sPath, "border"_ostr, "10%"); + + // And it must have the new 'gradient-stop' elements. + // The prefix 'loext' needs to be adapted, when the element is available in ODF strict. + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "offset"_ostr, "0"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-type"_ostr, "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-value"_ostr, "#ff0000"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "offset"_ostr, "0.3"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-type"_ostr, "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-value"_ostr, "#0099bb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[3]", "offset"_ostr, "1"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[3]", "color-type"_ostr, "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[3]", "color-value"_ostr, "#ffff00"); + + // Examine reloaded file + uno::Reference xShape(getShape(0)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + + // The old properties need to be still available, as they might be used in macros. + OUString sGradientName; + xShapeProperties->getPropertyValue("FillGradientName") >>= sGradientName; + CPPUNIT_ASSERT_EQUAL(u"threeStops"_ustr, sGradientName); + awt::Gradient2 aGradient; + xShapeProperties->getPropertyValue("FillGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xFF0000), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xFFFF00), aGradient.EndColor); + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_SQUARE, aGradient.Style); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), aGradient.XOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.YOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(450), aGradient.Angle); + CPPUNIT_ASSERT_EQUAL(sal_Int16(10), aGradient.Border); + + // Test new properties + auto aColorStopSeq = aGradient.ColorStops; + { + awt::ColorStop aColorStop = aColorStopSeq[0]; + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(Color(0xff0000), asColor(aColorStop.StopColor)); + } + { + awt::ColorStop aColorStop = aColorStopSeq[1]; + CPPUNIT_ASSERT_EQUAL(0.3, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(Color(0x0099bb), asColor(aColorStop.StopColor)); + } + { + awt::ColorStop aColorStop = aColorStopSeq[2]; + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(Color(0xffff00), asColor(aColorStop.StopColor)); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testBorderRestoration) +{ + // Load document. It has a shape with color gradient build from color stop yellow at offset 0.5 + // and color stop red at offset 1.0. For better backward compatibility such gradient has to be + // exported to ODF with a border of 50%. + // When gradient-stops are integrated in ODF strict, the test needs to be adapted. + + loadFromFile(u"MCGR_Border_restoration.pptx"); + + // Backup original ODF default version + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion(GetODFDefaultVersion()); + + // Save to ODF_LATEST which is currently ODF 1.3 extended. Make sure gradient-stop elements have + // offsets 0 and 1, and border is written as 50%. + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_LATEST); + save("impress8"); + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath + = "/office:document-styles/office:styles/draw:gradient[@draw:name='Gradient_20_1']"_ostr; + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-value"_ostr, "#ff0000"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "offset"_ostr, "1"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-value"_ostr, "#ffff00"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "offset"_ostr, "0"); + assertXPath(pXmlDoc, sPath, "border"_ostr, "50%"); + + // Save to ODF 1.3 strict and make sure border, start-color and end-color are suitable set. + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_013); + save("impress8"); + pXmlDoc = parseExport("styles.xml"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop", 0); + assertXPath(pXmlDoc, sPath, "start-color"_ostr, "#ffff00"); + assertXPath(pXmlDoc, sPath, "end-color"_ostr, "#ff0000"); + assertXPath(pXmlDoc, sPath, "border"_ostr, "50%"); + + // Set back to original ODF default version. + SetODFDefaultVersion(nCurrentODFVersion); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testTransparencyBorderRestoration) +{ + // Load document. It has a shape with transparency gradient build from transparency 100% at + // offset 0, transparency 100% at offset 0.4 and transparency 10% at offset 1.0. For better + // backward compatibility such gradient is exported with a border of 40% in the transparency + // gradient. The color itself is the same for all gradient stops. + // When transparency gradient-stops are integrated in ODF strict, the test needs to be adapted. + loadFromFile(u"MCGR_TransparencyBorder_restoration.pptx"); + + // Backup original ODF default version + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion(GetODFDefaultVersion()); + + // Save to ODF_LATEST which is currently ODF 1.3 extended. Make sure transparency gradient-stop + //elements are written with offset 0 and 1, and border is written as 40%. + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_LATEST); + save("impress8"); + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath = "/office:document-styles/office:styles/draw:opacity[1]"_ostr; + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[2]", "stop-opacity"_ostr, "0.9"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[2]", "offset"_ostr, "1"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[1]", "stop-opacity"_ostr, "0"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[1]", "offset"_ostr, "0"); + assertXPath(pXmlDoc, sPath, "border"_ostr, "40%"); + + // Save to ODF 1.3 strict and make sure border, start and end opacity are suitable set. + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_013); + save("impress8"); + pXmlDoc = parseExport("styles.xml"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop", 0); + assertXPath(pXmlDoc, sPath, "start"_ostr, "0%"); + assertXPath(pXmlDoc, sPath, "end"_ostr, "90%"); + assertXPath(pXmlDoc, sPath, "border"_ostr, "40%"); + + // Set back to original ODF default version. + SetODFDefaultVersion(nCurrentODFVersion); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testAxialGradientCompatible) +{ + // tdf#155549. An axial gradient with Border, StartColor A and EndColor B is exported to OOXML as + // symmetrical linear gradient with three stops, colors B A B. After the changes for multi-color + // gradients (MCGR) this is imported as linear gradient with colors B A B. So a consumer not able + // of MCGR would get a linear gradient with start and end color B. For better compatibility + // ODF export writes an axial gradient. with colors A and B. + // This test needs to be adapted when color stops are available in ODF strict and widely + // supported in even older LibreOffice versions. + loadFromFile(u"tdf155549_MCGR_AxialGradientCompatible.odt"); + + //Round-trip through OOXML. + // FixMe tdf#153183. Here "Attribute 'ID' is not allowed to appear in element 'v:rect'". + skipValidation(); + saveAndReload("Office Open XML Text"); + saveAndReload("writer8"); + + // Examine reloaded file + uno::Reference xShape(getShape(0)); + CPPUNIT_ASSERT_MESSAGE("No shape", xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + + // Without fix these would have failed with Style=0 (=LINEAR), StartColor=0xFFFF00 and Border=0. + awt::Gradient2 aGradient; + xShapeProperties->getPropertyValue("FillGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL_MESSAGE("gradient style", awt::GradientStyle_AXIAL, aGradient.Style); + CPPUNIT_ASSERT_EQUAL_MESSAGE("EndColor", sal_Int32(0xFFFF00), aGradient.EndColor); + CPPUNIT_ASSERT_EQUAL_MESSAGE("StartColor", sal_Int32(0x1E90FF), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Border", sal_Int16(20), aGradient.Border); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testAxialTransparencyCompatible) +{ + // tdf#155549. The shape in the document has a solid color and an axial transparency gradient + // with 'Transition start 60%', 'Start value 10%' and 'End value 80%'. The gradient is exported + // to OOXML as linear symmetrical gradient with three gradient stops. After the changes for + // multi-color gradients (MCGR) this is imported as linear transparency gradient. For better + // compatibility with consumers not able to use MCGR, the ODF export writes the transparency as + // axial transparency gradient that is same as in the original document. + // This test needs to be adapted when color stops are available in ODF strict and widely + // supported in even older LibreOffice versions. + loadFromFile(u"tdf155549_MCGR_AxialTransparencyCompatible.odt"); + + //Round-trip through OOXML. + // FixMe tdf#153183, and error in charSpace and in CharacterSet + //skipValidation(); + saveAndReload("Office Open XML Text"); + saveAndReload("writer8"); + + // Examine reloaded file + uno::Reference xShape(getShape(0)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + + // Without fix these would have failed with Style=LINEAR, StartColor=0xCCCCCC and wrong Border. + awt::Gradient2 aTransGradient; + xShapeProperties->getPropertyValue("FillTransparenceGradient") >>= aTransGradient; + CPPUNIT_ASSERT_EQUAL_MESSAGE("gradient style", awt::GradientStyle_AXIAL, aTransGradient.Style); + CPPUNIT_ASSERT_EQUAL_MESSAGE("EndColor", sal_Int32(0xCCCCCC), aTransGradient.EndColor); + CPPUNIT_ASSERT_EQUAL_MESSAGE("StartColor", sal_Int32(0x191919), aTransGradient.StartColor); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Border", sal_Int16(60), aTransGradient.Border); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/qa/unit/text.cxx b/xmloff/qa/unit/text.cxx new file mode 100644 index 0000000000..e6433b2b70 --- /dev/null +++ b/xmloff/qa/unit/text.cxx @@ -0,0 +1,1291 @@ +/* -*- 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 + +using namespace ::com::sun::star; + +/// Covers xmloff/source/text/ fixes. +class XmloffStyleTest : public UnoApiXmlTest +{ +public: + XmloffStyleTest(); +}; + +XmloffStyleTest::XmloffStyleTest() + : UnoApiXmlTest("/xmloff/qa/unit/data/") +{ +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testMailMergeInEditeng) +{ + // Without the accompanying fix in place, this test would have failed, as unexpected + // in editeng text aborted the whole import process. + loadFromFile(u"mail-merge-editeng.odt"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCommentProperty) +{ + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Sequence aCommentProps = comphelper::InitPropertySequence({ + { "Text", uno::Any(OUString("comment")) }, + }); + dispatchCommand(mxComponent, ".uno:InsertAnnotation", aCommentProps); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParaEnumAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParaEnum = xParaEnumAccess->createEnumeration(); + uno::Reference xPara(xParaEnum->nextElement(), uno::UNO_QUERY); + uno::Reference xPortionEnum = xPara->createEnumeration(); + uno::Reference xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY); + uno::Reference xField(xPortion->getPropertyValue("TextField"), + uno::UNO_QUERY); + xField->setPropertyValue("Resolved", uno::Any(true)); + xField->setPropertyValue("ParentName", uno::Any(OUString("parent_comment_name"))); + + saveAndReload("writer8"); + xTextDocument.set(mxComponent, uno::UNO_QUERY); + xParaEnumAccess.set(xTextDocument->getText(), uno::UNO_QUERY); + xParaEnum = xParaEnumAccess->createEnumeration(); + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + xPortionEnum = xPara->createEnumeration(); + xPortion.set(xPortionEnum->nextElement(), uno::UNO_QUERY); + xField.set(xPortion->getPropertyValue("TextField"), uno::UNO_QUERY); + bool bResolved = false; + xField->getPropertyValue("Resolved") >>= bResolved; + OUString parentName; + xField->getPropertyValue("ParentName") >>= parentName; + CPPUNIT_ASSERT_EQUAL( + OUString("parent_comment_name"), + parentName); // Check if the parent comment name is written and read correctly. + // Without the accompanying fix in place, this test would have failed, as the resolved state was + // not saved for non-range comments. + CPPUNIT_ASSERT(bResolved); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testBibliographyLocalUrl) +{ + // Given a document with a biblio field, with non-empty LocalURL: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference xField( + xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY); + uno::Sequence aFields = { + comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW), + comphelper::makePropertyValue("Identifier", OUString("AT")), + comphelper::makePropertyValue("Author", OUString("Author")), + comphelper::makePropertyValue("Title", OUString("Title")), + comphelper::makePropertyValue("URL", OUString("http://www.example.com/test.pdf#page=1")), + comphelper::makePropertyValue("LocalURL", OUString("file:///home/me/test.pdf")), + }; + xField->setPropertyValue("Fields", uno::Any(aFields)); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + uno::Reference xContent(xField, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false); + + // When invoking ODT export + import on it: + saveAndReload("writer8"); + // Without the accompanying fix in place, this test would have resulted in an assertion failure, + // as LocalURL was mapped to XML_TOKEN_INVALID. + + // Then make sure that LocalURL is preserved: + xTextDocument.set(mxComponent, uno::UNO_QUERY); + uno::Reference xParaEnumAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParaEnum = xParaEnumAccess->createEnumeration(); + uno::Reference xPara(xParaEnum->nextElement(), uno::UNO_QUERY); + uno::Reference xPortionEnum = xPara->createEnumeration(); + uno::Reference xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY); + xField.set(xPortion->getPropertyValue("TextField"), uno::UNO_QUERY); + comphelper::SequenceAsHashMap aMap(xField->getPropertyValue("Fields")); + CPPUNIT_ASSERT(aMap.contains("LocalURL")); + auto aActual = aMap["LocalURL"].get(); + CPPUNIT_ASSERT_EQUAL(OUString("file:///home/me/test.pdf"), aActual); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testBibliographyTargetURL1) +{ + // Given a document with a biblio field, with non-empty LocalURL: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference xField( + xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY); + uno::Sequence aFields = { + comphelper::makePropertyValue("Identifier", OUString("AT")), + comphelper::makePropertyValue("URL", OUString("https://display.url/test1.pdf#page=1")), + comphelper::makePropertyValue("TargetType", OUString("1")), + comphelper::makePropertyValue("TargetURL", OUString("https://target.url/test2.pdf#page=2")), + }; + xField->setPropertyValue("Fields", uno::Any(aFields)); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + uno::Reference xContent(xField, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false); + + // When invoking ODT export + import on it: + saveAndReload("writer8"); + + // Then make sure that URL, TargetURL and UseTargetURL are preserved and independent: + xTextDocument.set(mxComponent, uno::UNO_QUERY); + uno::Reference xParaEnumAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParaEnum = xParaEnumAccess->createEnumeration(); + uno::Reference xPara(xParaEnum->nextElement(), uno::UNO_QUERY); + uno::Reference xPortionEnum = xPara->createEnumeration(); + uno::Reference xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY); + xField.set(xPortion->getPropertyValue("TextField"), uno::UNO_QUERY); + comphelper::SequenceAsHashMap aMap(xField->getPropertyValue("Fields")); + + CPPUNIT_ASSERT(aMap.contains("URL")); + CPPUNIT_ASSERT_EQUAL(OUString("https://display.url/test1.pdf#page=1"), + aMap["URL"].get()); + + CPPUNIT_ASSERT(aMap.contains("TargetURL")); + CPPUNIT_ASSERT_EQUAL(OUString("https://target.url/test2.pdf#page=2"), + aMap["TargetURL"].get()); + + CPPUNIT_ASSERT(aMap.contains("TargetType")); + CPPUNIT_ASSERT_EQUAL(OUString("1"), aMap["TargetType"].get()); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCommentTableBorder) +{ + // Without the accompanying fix in place, this failed to load, as a comment that started in a + // table and ended outside a table aborted the whole importer. + loadFromFile(u"comment-table-border.fodt"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testParaStyleListLevel) +{ + // Given a document with style:list-level="...": + loadFromFile(u"para-style-list-level.fodt"); + + // Then make sure we map that to the paragraph style's numbering level: + uno::Reference xStyleFamiliesSupplier(mxComponent, + uno::UNO_QUERY); + uno::Reference xStyleFamilies + = xStyleFamiliesSupplier->getStyleFamilies(); + uno::Reference xStyleFamily( + xStyleFamilies->getByName("ParagraphStyles"), uno::UNO_QUERY); + uno::Reference xStyle(xStyleFamily->getByName("mystyle"), uno::UNO_QUERY); + sal_Int16 nNumberingLevel{}; + CPPUNIT_ASSERT(xStyle->getPropertyValue("NumberingLevel") >>= nNumberingLevel); + CPPUNIT_ASSERT_EQUAL(static_cast(1), nNumberingLevel); + + // Test the export as well: + save("writer8"); + + // Then make sure we save the style's numbering level: + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + // Without the accompanying fix in place, this failed with: + // - XPath '/office:document-styles/office:styles/style:style[@style:name='mystyle']' no attribute 'list-level' exist + // i.e. a custom NumberingLevel was lost on save. + assertXPath(pXmlDoc, + "/office:document-styles/office:styles/style:style[@style:name='mystyle']"_ostr, + "list-level"_ostr, "2"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testContinueNumberingWord) +{ + // Given a document, which is produced by Word and contains text:continue-numbering="true": + loadFromFile(u"continue-numbering-word.odt"); + + // Then make sure that the numbering from the 1st para is continued on the 3rd para: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xParaEnumAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParaEnum = xParaEnumAccess->createEnumeration(); + xParaEnum->nextElement(); + xParaEnum->nextElement(); + uno::Reference xPara(xParaEnum->nextElement(), uno::UNO_QUERY); + auto aActual = xPara->getPropertyValue("ListLabelString").get(); + // Without the accompanying fix in place, this failed with: + // - Expected: 2. + // - Actual : 1. + // i.e. the numbering was not continued, like in Word. + CPPUNIT_ASSERT_EQUAL(OUString("2."), aActual); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testListId) +{ + // Given a document with a simple list (no continue-list="..." attribute): + loadFromFile(u"list-id.fodt"); + + // When storing that document as ODF: + save("writer8"); + + // Then make sure that unreferenced xml:id="..." attributes are not written: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this failed with: + // - XPath '//text:list' unexpected 'id' attribute + // i.e. xml:id="..." was written unconditionally, even when no other list needed it. + assertXPathNoAttribute(pXmlDoc, "//text:list"_ostr, "id"_ostr); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testListId2) +{ + // tdf#155823 Given a document with a list consisting of items having different list styles: + loadFromFile(u"differentListStylesInOneList.fodt"); + + auto xTextDocument(mxComponent.queryThrow()); + auto xParaEnumAccess(xTextDocument->getText().queryThrow()); + auto xParaEnum(xParaEnumAccess->createEnumeration()); + + auto xPara(xParaEnum->nextElement().queryThrow()); + auto aActual(xPara->getPropertyValue("ListLabelString").get()); + CPPUNIT_ASSERT_EQUAL(OUString("1."), aActual); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("2."), aActual); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("3."), aActual); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("4."), aActual); + + // When storing that document as ODF: + // Without the fix in place, automatic validation would fail with: + // Error: "list123456789012345" is referenced by an IDREF, but not defined. + saveAndReload("writer8"); + + xTextDocument.set(mxComponent.queryThrow()); + xParaEnumAccess.set(xTextDocument->getText().queryThrow()); + xParaEnum.set(xParaEnumAccess->createEnumeration()); + + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("1."), aActual); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("2."), aActual); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("3."), aActual); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + + // Check that the last item number is correct + + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + aActual = xPara->getPropertyValue("ListLabelString").get(); + // Without the fix in place, this would fail with: + // - Expected: 4. + // - Actual : 1. + // i.e. the numbering was not continued. + CPPUNIT_ASSERT_EQUAL(OUString("4."), aActual); + + // Then make sure that required xml:id="..." attributes is written when the style changes: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + CPPUNIT_ASSERT(pXmlDoc); + // Without the fix in place, this would fail, + // i.e. xml:id="..." was omitted, even though it was needed for the next item. + OUString id = getXPath( + pXmlDoc, "/office:document-content/office:body/office:text/text:list[3]"_ostr, "id"_ostr); + CPPUNIT_ASSERT(!id.isEmpty()); + assertXPath(pXmlDoc, "/office:document-content/office:body/office:text/text:list[4]"_ostr, + "continue-list"_ostr, id); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testListIdState) +{ + // tdf#149668: given a document with 3 paragraphs: an outer numbering on para 1 & 3, an inner + // numbering on para 2: + mxComponent = loadFromDesktop("private:factory/swriter"); + auto xTextDocument(mxComponent.queryThrow()); + auto xText(xTextDocument->getText()); + xText->insertControlCharacter(xText->getEnd(), css::text::ControlCharacter::PARAGRAPH_BREAK, + false); + xText->insertControlCharacter(xText->getEnd(), css::text::ControlCharacter::PARAGRAPH_BREAK, + false); + + auto paraEnumAccess(xText.queryThrow()); + auto paraEnum(paraEnumAccess->createEnumeration()); + auto xParaProps(paraEnum->nextElement().queryThrow()); + xParaProps->setPropertyValue("NumberingStyleName", css::uno::Any(OUString("Numbering ABC"))); + xParaProps.set(paraEnum->nextElement().queryThrow()); + xParaProps->setPropertyValue("NumberingStyleName", css::uno::Any(OUString("Numbering 123"))); + xParaProps.set(paraEnum->nextElement().queryThrow()); + xParaProps->setPropertyValue("NumberingStyleName", css::uno::Any(OUString("Numbering ABC"))); + + // When storing that document as ODF: + save("writer8"); + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + + // Make sure that xml:id="..." gets written for para 1, as it'll be continued in para 3. + // Without the accompanying fix in place, this test would have failed, + // i.e. para 1 didn't write an xml:id="..." but para 3 referred to it using continue-list="...", + // which is inconsistent. + OUString id = getXPath( + pXmlDoc, "/office:document-content/office:body/office:text/text:list[1]"_ostr, "id"_ostr); + CPPUNIT_ASSERT(!id.isEmpty()); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testListIdOnRestart) +{ + // Test that a restart of a continued list, by itself, does not introduce a unneeded xml:id + // and text:continue-list, but uses text:continue-numbering, and is imported correctly. + + // Given a document with a list with a restart after break: + loadFromFile(u"listRestartAfterBreak.fodt"); + + auto xTextDocument(mxComponent.queryThrow()); + auto xParaEnumAccess(xTextDocument->getText().queryThrow()); + auto xParaEnum(xParaEnumAccess->createEnumeration()); + + auto xPara(xParaEnum->nextElement().queryThrow()); + auto aActual(xPara->getPropertyValue("ListLabelString").get()); + CPPUNIT_ASSERT_EQUAL(OUString("1."), aActual); + OUString list_id = xPara->getPropertyValue("ListId").get(); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY_THROW); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("2."), aActual); + CPPUNIT_ASSERT_EQUAL(list_id, xPara->getPropertyValue("ListId").get()); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + aActual = xPara->getPropertyValue("ListLabelString").get(); + // Check that restart was applied correctly, with simple 'text:continue-numbering="true"' + CPPUNIT_ASSERT_EQUAL(OUString("1."), aActual); + CPPUNIT_ASSERT_EQUAL(list_id, xPara->getPropertyValue("ListId").get()); + + // When storing that document as ODF: + saveAndReload("writer8"); + + xTextDocument.set(mxComponent, uno::UNO_QUERY_THROW); + xParaEnumAccess.set(xTextDocument->getText(), uno::UNO_QUERY_THROW); + xParaEnum.set(xParaEnumAccess->createEnumeration()); + + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY_THROW); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("1."), aActual); + list_id = xPara->getPropertyValue("ListId").get(); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY_THROW); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("2."), aActual); + CPPUNIT_ASSERT_EQUAL(list_id, xPara->getPropertyValue("ListId").get()); + xParaEnum->nextElement(); // Skip empty intermediate paragraph + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY_THROW); + aActual = xPara->getPropertyValue("ListLabelString").get(); + CPPUNIT_ASSERT_EQUAL(OUString("1."), aActual); + CPPUNIT_ASSERT_EQUAL(list_id, xPara->getPropertyValue("ListId").get()); + + // Then make sure that no xml:id="..." attribute is written, even in restarted case: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + CPPUNIT_ASSERT(pXmlDoc); + assertXPath(pXmlDoc, "//text:list"_ostr, 3); + assertXPathNoAttribute(pXmlDoc, "//text:list[1]"_ostr, "id"_ostr); + assertXPathNoAttribute(pXmlDoc, "//text:list[2]"_ostr, "id"_ostr); + assertXPathNoAttribute(pXmlDoc, "//text:list[3]"_ostr, "id"_ostr); + assertXPathNoAttribute(pXmlDoc, "//text:list[3]"_ostr, "continue-list"_ostr); + assertXPath(pXmlDoc, "//text:list[3]"_ostr, "continue-numbering"_ostr, "true"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testClearingBreakExport) +{ + // Given a document with a clearing break: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xLineBreak( + xMSF->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + uno::Reference xLineBreakProps(xLineBreak, uno::UNO_QUERY); + // SwLineBreakClear::ALL; + sal_Int16 eClear = 3; + xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false); + + // When exporting to ODT: + save("writer8"); + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this failed with: + // - XPath '//text:line-break' number of nodes is incorrect + // i.e. the clearing break was lost on export. + assertXPath(pXmlDoc, "//text:line-break"_ostr, "clear"_ostr, "all"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testClearingBreakImport) +{ + // Given an ODF document with a clearing break: + loadFromFile(u"clearing-break.fodt"); + + // Then make sure that the "clear" attribute is not lost on import: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + // First portion is the image. + xPortions->nextElement(); + // Second portion is "foo". + xPortions->nextElement(); + // Without the accompanying fix in place, this failed with: + // An uncaught exception of type com.sun.star.container.NoSuchElementException + // i.e. the line break was a non-clearing one, so we only had 2 portions, not 4 (image, text, + // linebreak, text). + uno::Reference xPortion(xPortions->nextElement(), uno::UNO_QUERY); + OUString aTextPortionType; + xPortion->getPropertyValue("TextPortionType") >>= aTextPortionType; + CPPUNIT_ASSERT_EQUAL(OUString("LineBreak"), aTextPortionType); + uno::Reference xLineBreak; + xPortion->getPropertyValue("LineBreak") >>= xLineBreak; + uno::Reference xLineBreakProps(xLineBreak, uno::UNO_QUERY); + sal_Int16 eClear{}; + xLineBreakProps->getPropertyValue("Clear") >>= eClear; + CPPUNIT_ASSERT_EQUAL(static_cast(3), eClear); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testRelativeWidth) +{ + // Given a document with an 50% wide text frame: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xStyleFamiliesSupplier(mxComponent, + uno::UNO_QUERY); + uno::Reference xStyleFamilies + = xStyleFamiliesSupplier->getStyleFamilies(); + uno::Reference xStyleFamily(xStyleFamilies->getByName("PageStyles"), + uno::UNO_QUERY); + uno::Reference xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY); + // Body frame width is 6cm (2+2cm margin). + xStyle->setPropertyValue("Width", uno::Any(static_cast(10000))); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xTextFrame( + xMSF->createInstance("com.sun.star.text.TextFrame"), uno::UNO_QUERY); + uno::Reference xTextFrameProps(xTextFrame, uno::UNO_QUERY); + xTextFrameProps->setPropertyValue("RelativeWidth", uno::Any(static_cast(50))); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertTextContent(xCursor, xTextFrame, /*bAbsorb=*/false); + // Body frame width is 16cm. + xStyle->setPropertyValue("Width", uno::Any(static_cast(20000))); + + save("writer8"); + + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this failed with: + // - Expected: 3.1492in (8cm) + // - Actual : 0.0161in (0.04 cm) + // i.e. the fallback width value wasn't the expected half of the body frame width, but a smaller + // value. + assertXPath(pXmlDoc, "//draw:frame"_ostr, "width"_ostr, "3.1492in"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testScaleWidthAndHeight) +{ + // Given a broken document where both IsSyncHeightToWidth and IsSyncWidthToHeight are set to + // true: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xTextFrame( + xMSF->createInstance("com.sun.star.text.TextFrame"), uno::UNO_QUERY); + uno::Reference xTextFrameProps(xTextFrame, uno::UNO_QUERY); + xTextFrameProps->setPropertyValue("Width", uno::Any(static_cast(2000))); + xTextFrameProps->setPropertyValue("Height", uno::Any(static_cast(1000))); + xTextFrameProps->setPropertyValue("IsSyncHeightToWidth", uno::Any(true)); + xTextFrameProps->setPropertyValue("IsSyncWidthToHeight", uno::Any(true)); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertTextContent(xCursor, xTextFrame, /*bAbsorb=*/false); + + // When exporting to ODT: + save("writer8"); + + // Then make sure that we still export a non-zero size: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this failed with: + // - Expected: 0.7874in + // - Actual : 0in + // i.e. the exported size was 0, not 2000 mm100 in inches. + assertXPath(pXmlDoc, "//draw:frame"_ostr, "width"_ostr, "0.7874in"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testContentControlExport) +{ + // Given a document with a content control around one or more text portions: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertString(xCursor, "test", /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + xContentControlProps->setPropertyValue("ShowingPlaceHolder", uno::Any(true)); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to ODT: + save("writer8"); + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this failed with: + // - XPath '//loext:content-control' number of nodes is incorrect + // i.e. the content control was lost on export. + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "showing-place-holder"_ostr, "true"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testContentControlImport) +{ + // Given an ODF document with a content control: + loadFromFile(u"content-control.fodt"); + + // Then make sure that the content control is not lost on import: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + uno::Reference xTextPortion(xPortions->nextElement(), uno::UNO_QUERY); + OUString aPortionType; + xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType; + // Without the accompanying fix in place, this failed with: + // - Expected: ContentControl + // - Actual : Text + // i.e. the content control was lost on import. + CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType); + uno::Reference xContentControl; + xTextPortion->getPropertyValue("ContentControl") >>= xContentControl; + uno::Reference xContentControlRange(xContentControl, uno::UNO_QUERY); + uno::Reference xText = xContentControlRange->getText(); + uno::Reference xContentEnumAccess(xText, uno::UNO_QUERY); + uno::Reference xContentEnum = xContentEnumAccess->createEnumeration(); + uno::Reference xContent(xContentEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("test"), xContent->getString()); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCheckboxContentControlExport) +{ + // Given a document with a checkbox content control around a text portion: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertString(xCursor, u"☐"_ustr, /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + xContentControlProps->setPropertyValue("Checkbox", uno::Any(true)); + xContentControlProps->setPropertyValue("Checked", uno::Any(true)); + xContentControlProps->setPropertyValue("CheckedState", uno::Any(u"☒"_ustr)); + xContentControlProps->setPropertyValue("UncheckedState", uno::Any(u"☐"_ustr)); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to ODT: + save("writer8"); + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "checkbox"_ostr, "true"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "checked"_ostr, "true"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "checked-state"_ostr, u"☒"_ustr); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "unchecked-state"_ostr, u"☐"_ustr); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCheckboxContentControlImport) +{ + // Given an ODF document with a checkbox content control: + loadFromFile(u"content-control-checkbox.fodt"); + + // Then make sure that the content control is not lost on import: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + uno::Reference xTextPortion(xPortions->nextElement(), 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 bCheckbox{}; + xContentControlProps->getPropertyValue("Checkbox") >>= bCheckbox; + // Without the accompanying fix in place, this failed, as the checkbox-related attributes were + // ignored on import. + CPPUNIT_ASSERT(bCheckbox); + bool bChecked{}; + xContentControlProps->getPropertyValue("Checked") >>= bChecked; + CPPUNIT_ASSERT(bChecked); + OUString aCheckedState; + xContentControlProps->getPropertyValue("CheckedState") >>= aCheckedState; + CPPUNIT_ASSERT_EQUAL(u"☒"_ustr, aCheckedState); + OUString aUncheckedState; + xContentControlProps->getPropertyValue("UncheckedState") >>= aUncheckedState; + CPPUNIT_ASSERT_EQUAL(u"☐"_ustr, aUncheckedState); + uno::Reference xContentControlRange(xContentControl, uno::UNO_QUERY); + uno::Reference xText = xContentControlRange->getText(); + uno::Reference xContentEnumAccess(xText, uno::UNO_QUERY); + uno::Reference xContentEnum = xContentEnumAccess->createEnumeration(); + uno::Reference xContent(xContentEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(u"☒"_ustr, xContent->getString()); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDropdownContentControlExport) +{ + // Given a document with a dropdown content control around a text portion: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertString(xCursor, "choose an item", /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + { + xContentControlProps->setPropertyValue("DropDown", uno::Any(true)); + uno::Sequence aListItems = { + { + comphelper::makePropertyValue("DisplayText", uno::Any(OUString("red"))), + comphelper::makePropertyValue("Value", uno::Any(OUString("R"))), + }, + { + comphelper::makePropertyValue("DisplayText", uno::Any(OUString("green"))), + comphelper::makePropertyValue("Value", uno::Any(OUString("G"))), + }, + { + comphelper::makePropertyValue("DisplayText", uno::Any(OUString("blue"))), + comphelper::makePropertyValue("Value", uno::Any(OUString("B"))), + }, + }; + xContentControlProps->setPropertyValue("ListItems", uno::Any(aListItems)); + } + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to ODT: + save("writer8"); + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "dropdown"_ostr, "true"); + // Without the accompanying fix in place, this failed with: + // - Expected: 1 + // - Actual : 0 + // - XPath '//loext:content-control/loext:list-item[1]' number of nodes is incorrect + // i.e. the list items were lost on export. + assertXPath(pXmlDoc, "//loext:content-control/loext:list-item[1]"_ostr, "display-text"_ostr, + "red"); + assertXPath(pXmlDoc, "//loext:content-control/loext:list-item[1]"_ostr, "value"_ostr, "R"); + assertXPath(pXmlDoc, "//loext:content-control/loext:list-item[2]"_ostr, "display-text"_ostr, + "green"); + assertXPath(pXmlDoc, "//loext:content-control/loext:list-item[2]"_ostr, "value"_ostr, "G"); + assertXPath(pXmlDoc, "//loext:content-control/loext:list-item[3]"_ostr, "display-text"_ostr, + "blue"); + assertXPath(pXmlDoc, "//loext:content-control/loext:list-item[3]"_ostr, "value"_ostr, "B"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDropdownContentControlImport) +{ + // Given an ODF document with a dropdown content control: + loadFromFile(u"content-control-dropdown.fodt"); + + // Then make sure that the content control is not lost on import: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + uno::Reference xTextPortion(xPortions->nextElement(), 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); + uno::Sequence aListItems; + xContentControlProps->getPropertyValue("ListItems") >>= aListItems; + // Without the accompanying fix in place, this failed with: + // - Expected: 3 + // - Actual : 0 + // i.e. the list items were lost on import. + CPPUNIT_ASSERT_EQUAL(static_cast(3), aListItems.getLength()); + comphelper::SequenceAsHashMap aMap0(aListItems[0]); + CPPUNIT_ASSERT_EQUAL(OUString("red"), aMap0["DisplayText"].get()); + CPPUNIT_ASSERT_EQUAL(OUString("R"), aMap0["Value"].get()); + comphelper::SequenceAsHashMap aMap1(aListItems[1]); + CPPUNIT_ASSERT_EQUAL(OUString("green"), aMap1["DisplayText"].get()); + CPPUNIT_ASSERT_EQUAL(OUString("G"), aMap1["Value"].get()); + comphelper::SequenceAsHashMap aMap2(aListItems[2]); + CPPUNIT_ASSERT_EQUAL(OUString("blue"), aMap2["DisplayText"].get()); + CPPUNIT_ASSERT_EQUAL(OUString("B"), aMap2["Value"].get()); + uno::Reference xContentControlRange(xContentControl, uno::UNO_QUERY); + uno::Reference xText = xContentControlRange->getText(); + uno::Reference xContentEnumAccess(xText, uno::UNO_QUERY); + uno::Reference xContentEnum = xContentEnumAccess->createEnumeration(); + uno::Reference xContent(xContentEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("choose a color"), xContent->getString()); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testPictureContentControlExport) +{ + // Given a document with a picture content control around an as-char image: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + uno::Reference xTextGraphic( + xMSF->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); + xTextGraphic->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AS_CHARACTER)); + uno::Reference xTextContent(xTextGraphic, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xTextContent, false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + xContentControlProps->setPropertyValue("Picture", uno::Any(true)); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to ODT: + save("writer8"); + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this test would have failed with: + // - XPath '//loext:content-control' no attribute 'picture' exist + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "picture"_ostr, "true"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testPictureContentControlImport) +{ + // Given an ODF document with a picture content control: + loadFromFile(u"content-control-picture.fodt"); + + // Then make sure that the content control is not lost on import: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + uno::Reference xTextPortion(xPortions->nextElement(), 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 bPicture{}; + xContentControlProps->getPropertyValue("Picture") >>= bPicture; + // Without the accompanying fix in place, this failed, as the picture attribute was ignored on + // import. + CPPUNIT_ASSERT(bPicture); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDateContentControlExport) +{ + // Given a document with a date content control around a text portion: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertString(xCursor, "choose a date", /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + xContentControlProps->setPropertyValue("Date", uno::Any(true)); + xContentControlProps->setPropertyValue("DateFormat", uno::Any(OUString("YYYY-MM-DD"))); + xContentControlProps->setPropertyValue("DateLanguage", uno::Any(OUString("en-US"))); + xContentControlProps->setPropertyValue("CurrentDate", + uno::Any(OUString("2022-05-25T00:00:00Z"))); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to ODT: + save("writer8"); + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this test would have failed with: + // - XPath '//loext:content-control' no attribute 'date' exist + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "date"_ostr, "true"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "date-format"_ostr, "YYYY-MM-DD"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "date-rfc-language-tag"_ostr, "en-US"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "current-date"_ostr, + "2022-05-25T00:00:00Z"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDateContentControlImport) +{ + // Given an ODF document with a date content control: + loadFromFile(u"content-control-date.fodt"); + + // Then make sure that the content control is not lost on import: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + uno::Reference xTextPortion(xPortions->nextElement(), 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; + // Without the accompanying fix in place, this test would have failed, the content control was + // imported as a default rich text one. + CPPUNIT_ASSERT(bDate); + OUString aDateFormat; + xContentControlProps->getPropertyValue("DateFormat") >>= aDateFormat; + CPPUNIT_ASSERT_EQUAL(OUString("YYYY-MM-DD"), aDateFormat); + OUString aDateLanguage; + xContentControlProps->getPropertyValue("DateLanguage") >>= aDateLanguage; + CPPUNIT_ASSERT_EQUAL(OUString("en-US"), aDateLanguage); + OUString aCurrentDate; + xContentControlProps->getPropertyValue("CurrentDate") >>= aCurrentDate; + CPPUNIT_ASSERT_EQUAL(OUString("2022-05-25T00:00:00Z"), aCurrentDate); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testPlainTextContentControlExport) +{ + // Given a document with a plain text content control around a text portion: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertString(xCursor, "test", /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + xContentControlProps->setPropertyValue("PlainText", uno::Any(true)); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to ODT: + save("writer8"); + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this test would have failed with: + // - XPath '//loext:content-control' no attribute 'plain-text' exist + // i.e. the plain text content control was turned into a rich text one on export. + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "plain-text"_ostr, "true"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testPlainTextContentControlImport) +{ + // Given an ODF document with a plain-text content control: + loadFromFile(u"content-control-plain-text.fodt"); + + // Then make sure that the content control is not lost on import: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + uno::Reference xTextPortion(xPortions->nextElement(), 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 bPlainText{}; + xContentControlProps->getPropertyValue("PlainText") >>= bPlainText; + // Without the accompanying fix in place, this test would have failed, the import result was a + // rich text content control (not a plain text one). + CPPUNIT_ASSERT(bPlainText); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testComboBoxContentControlExport) +{ + // Given a document with a combo box content control around a text portion: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertString(xCursor, "test", /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + xContentControlProps->setPropertyValue("ComboBox", uno::Any(true)); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to ODT: + save("writer8"); + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this test would have failed with: + // - XPath '//loext:content-control' no attribute 'combobox' exist + // i.e. the combo box content control was turned into a drop-down one on export. + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "combobox"_ostr, "true"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testAliasContentControlExport) +{ + // Given a document with a content control and its alias around a text portion: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + xText->insertString(xCursor, "test", /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("my alias"))); + xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("my tag"))); + xContentControlProps->setPropertyValue("Id", uno::Any(static_cast(-2147483648))); + xContentControlProps->setPropertyValue("TabIndex", uno::Any(sal_uInt32(3))); + xContentControlProps->setPropertyValue("Lock", uno::Any(OUString("unlocked"))); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to ODT: + save("writer8"); + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this test would have failed with: + // - Expression: prop + // - XPath '//loext:content-control' no attribute 'alias' exist + // i.e. alias was lost on export. + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "alias"_ostr, "my alias"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "tag"_ostr, "my tag"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "id"_ostr, "-2147483648"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "tab-index"_ostr, "3"); + assertXPath(pXmlDoc, "//loext:content-control"_ostr, "lock"_ostr, "unlocked"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testComboBoxContentControlImport) +{ + // Given an ODF document with a plain-text content control: + loadFromFile(u"content-control-combo-box.fodt"); + + // Then make sure that the content control is not lost on import: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + uno::Reference xTextPortion(xPortions->nextElement(), 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 bComboBox{}; + xContentControlProps->getPropertyValue("ComboBox") >>= bComboBox; + // Without the accompanying fix in place, this test would have failed, the import result was a + // drop-down content control (not a combo box one). + CPPUNIT_ASSERT(bComboBox); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testAliasContentControlImport) +{ + // Given an ODF document with a content control and its alias/tag: + loadFromFile(u"content-control-alias.fodt"); + + // Then make sure that the content control is not lost on import: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + uno::Reference xTextPortion(xPortions->nextElement(), 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); + OUString aAlias; + xContentControlProps->getPropertyValue("Alias") >>= aAlias; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: my alias + // - Actual : + // i.e. the alias was lost on import. + CPPUNIT_ASSERT_EQUAL(OUString("my alias"), aAlias); + OUString aTag; + xContentControlProps->getPropertyValue("Tag") >>= aTag; + CPPUNIT_ASSERT_EQUAL(OUString("my tag"), aTag); + sal_Int32 nId = 0; + xContentControlProps->getPropertyValue("Id") >>= nId; + CPPUNIT_ASSERT_EQUAL(static_cast(2147483647), nId); + sal_uInt32 nTabIndex; + xContentControlProps->getPropertyValue("TabIndex") >>= nTabIndex; + CPPUNIT_ASSERT_EQUAL(static_cast(4), nTabIndex); + OUString aLock; + xContentControlProps->getPropertyValue("Lock") >>= aLock; + CPPUNIT_ASSERT_EQUAL(OUString("sdtContentLocked"), aLock); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDropdownContentControlAutostyleExport) +{ + // Given a document with a dropdown content control, and formatting that forms an autostyle in + // ODT: + loadFromFile(u"content-control-dropdown.docx"); + + // When saving that document to ODT, then make sure no assertion failure happens: + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + uno::Sequence aStoreProps = comphelper::InitPropertySequence({ + { "FilterName", uno::Any(OUString("writer8")) }, + }); + // Without the accompanying fix in place, this test would have failed, we had duplicated XML + // attributes. + xStorable->storeToURL(maTempFile.GetURL(), aStoreProps); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testScaleWidthRedline) +{ + // Given a document with change tracking enabled, one image is part of a delete redline: + loadFromFile(u"scale-width-redline.fodt"); + dispatchCommand(mxComponent, ".uno:TrackChanges", {}); + dispatchCommand(mxComponent, ".uno:GoToEndOfLine", {}); + dispatchCommand(mxComponent, ".uno:EndOfParaSel", {}); + dispatchCommand(mxComponent, ".uno:Delete", {}); + + // When saving to ODT: + save("writer8"); + + // Then make sure that a non-zero size is written to the output: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 6.1728in + // - Actual : 0in + // i.e. the deleted image had zero size, which is incorrect. + assertXPath(pXmlDoc, "//draw:frame[@draw:name='Image45']"_ostr, "width"_ostr, "6.1728in"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testThemeExport) +{ + mxComponent = loadFromDesktop("private:factory/swriter"); + + uno::Reference xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); + uno::Reference xPageProps(xDrawPage, uno::UNO_QUERY); + + auto pTheme = std::make_shared("My Theme"); + auto pColorSet = std::make_shared("My Color Scheme"); + pColorSet->add(model::ThemeColorType::Dark1, 0x101010); + pColorSet->add(model::ThemeColorType::Light1, 0x202020); + pColorSet->add(model::ThemeColorType::Dark2, 0x303030); + pColorSet->add(model::ThemeColorType::Light2, 0x404040); + pColorSet->add(model::ThemeColorType::Accent1, 0x505050); + pColorSet->add(model::ThemeColorType::Accent2, 0x606060); + pColorSet->add(model::ThemeColorType::Accent3, 0x707070); + pColorSet->add(model::ThemeColorType::Accent4, 0x808080); + pColorSet->add(model::ThemeColorType::Accent5, 0x909090); + pColorSet->add(model::ThemeColorType::Accent6, 0xa0a0a0); + pColorSet->add(model::ThemeColorType::Hyperlink, 0xb0b0b0); + pColorSet->add(model::ThemeColorType::FollowedHyperlink, 0xc0c0c0); + pTheme->setColorSet(pColorSet); + + uno::Reference xTheme = model::theme::createXTheme(pTheme); + xPageProps->setPropertyValue("Theme", uno::Any(xTheme)); + + // Export to ODT: + save("writer8"); + + // Check if the 12 colors are written in the XML: + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString aThemePath = "//office:styles/loext:theme/loext:theme-colors/loext:color"_ostr; + assertXPath(pXmlDoc, aThemePath, 12); + assertXPath(pXmlDoc, aThemePath + "[1]", "name"_ostr, "dark1"); + assertXPath(pXmlDoc, aThemePath + "[1]", "color"_ostr, "#101010"); + assertXPath(pXmlDoc, aThemePath + "[2]", "name"_ostr, "light1"); + assertXPath(pXmlDoc, aThemePath + "[2]", "color"_ostr, "#202020"); + assertXPath(pXmlDoc, aThemePath + "[12]", "name"_ostr, "followed-hyperlink"); + assertXPath(pXmlDoc, aThemePath + "[12]", "color"_ostr, "#c0c0c0"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testFloatingTableExport) +{ + // Given a document with a floating table: + mxComponent = loadFromDesktop("private:factory/swriter"); + // Insert a table: + uno::Sequence aArgs = { + comphelper::makePropertyValue("Rows", static_cast(1)), + comphelper::makePropertyValue("Columns", static_cast(1)), + }; + dispatchCommand(mxComponent, ".uno:InsertTable", aArgs); + // Select it: + dispatchCommand(mxComponent, ".uno:SelectAll", {}); + // Wrap in a fly: + aArgs = { + comphelper::makePropertyValue("AnchorType", static_cast(0)), + }; + dispatchCommand(mxComponent, ".uno:InsertFrame", aArgs); + // Mark it as a floating table: + uno::Reference xTextFramesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xFrame( + xTextFramesSupplier->getTextFrames()->getByName("Frame1"), uno::UNO_QUERY); + xFrame->setPropertyValue("IsSplitAllowed", uno::Any(true)); + + // When saving to ODT: + save("writer8"); + + // Then make sure we write a floating table, not a textframe containing a table: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this test would have failed with: + // - XPath '//draw:frame' no attribute 'may-break-between-pages' exist + // i.e. no floating table was exported. + assertXPath(pXmlDoc, "//draw:frame"_ostr, "may-break-between-pages"_ostr, "true"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testFloatingTableImport) +{ + // Given a document with a floating table (loext:may-break-between-pages="true"), when importing + // that document: + loadFromFile(u"floattable.fodt"); + + // Then make sure that the matching text frame property is set: + uno::Reference xTextFramesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xFrame( + xTextFramesSupplier->getTextFrames()->getByName("Frame1"), uno::UNO_QUERY); + bool bIsSplitAllowed = false; + // Without the accompanying fix in place, this test would have failed, the property was false. + xFrame->getPropertyValue("IsSplitAllowed") >>= bIsSplitAllowed; + CPPUNIT_ASSERT(bIsSplitAllowed); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testParagraphScopedTabDistance) +{ + // Given a document with paragraph scoped default tab stop distance (loext:tab-stop-distance="0.5cm") + loadFromFile(u"paragraph-tab-stop-distance.fodp"); + + uno::Reference xDoc(mxComponent, uno::UNO_QUERY); + uno::Reference xPage(xDoc->getDrawPages()->getByIndex(0), + uno::UNO_QUERY_THROW); + + uno::Reference xShape(xPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference xText + = uno::Reference(xShape, uno::UNO_QUERY_THROW)->getText(); + + uno::Reference paraEnumAccess(xText, uno::UNO_QUERY); + uno::Reference paraEnum(paraEnumAccess->createEnumeration()); + uno::Reference xParagraph(paraEnum->nextElement(), uno::UNO_QUERY_THROW); + + uno::Reference runEnumAccess(xParagraph, uno::UNO_QUERY); + uno::Reference runEnum = runEnumAccess->createEnumeration(); + uno::Reference xRun(runEnum->nextElement(), uno::UNO_QUERY); + uno::Reference xPropSet(xRun, uno::UNO_QUERY_THROW); + + // Make sure the tab stop default distance is imported correctly + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 10000 + // - Actual : 0 + CPPUNIT_ASSERT_EQUAL(static_cast(10000), + xPropSet->getPropertyValue("ParaTabStopDefaultDistance").get()); + + // Save the imported file to test the export too + save("impress8"); + + // Then make sure we write the tab-stop-distance + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath(pXmlDoc, "//style:style[@style:name='P1']/style:paragraph-properties"_ostr, + "tab-stop-distance"_ostr, "10cm"); + + assertXPath(pXmlDoc, "//text:p[@text:style-name='P1']"_ostr); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testNestedSpans) +{ + // Given a document with a first paragraph that has a nested span, the outer span setting the + // boldness: + // When importing that document: + loadFromFile(u"nested-spans.odt"); + + // Then make sure the text portion is bold, not normal: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + uno::Reference xTextPortion(xPortions->nextElement(), uno::UNO_QUERY); + float fWeight{}; + xTextPortion->getPropertyValue("CharWeight") >>= fWeight; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 150 (awt::FontWeight::BOLD) + // - Actual : 100 (awt::FontWeight::NORMAL) + // i.e. the boldness was lost on import. + CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, fWeight); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/qa/unit/text/txtprmap.cxx b/xmloff/qa/unit/text/txtprmap.cxx new file mode 100644 index 0000000000..08c91c4c1a --- /dev/null +++ b/xmloff/qa/unit/text/txtprmap.cxx @@ -0,0 +1,87 @@ +/* -*- 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 + +using namespace ::com::sun::star; + +namespace +{ +/// Covers xmloff/source/text/txtprmap.cxx fixes. +class Test : public UnoApiXmlTest +{ +public: + Test(); +}; +} + +Test::Test() + : UnoApiXmlTest("/xmloff/qa/unit/data/") +{ +} + +CPPUNIT_TEST_FIXTURE(Test, testFloatingTableWrapTextAtFlyStartExport) +{ + // Given a document with a floating table: + mxComponent = loadFromDesktop("private:factory/swriter"); + // Insert a table: + uno::Sequence aArgs = { + comphelper::makePropertyValue("Rows", static_cast(1)), + comphelper::makePropertyValue("Columns", static_cast(1)), + }; + dispatchCommand(mxComponent, ".uno:InsertTable", aArgs); + // Select it: + dispatchCommand(mxComponent, ".uno:SelectAll", {}); + // Wrap in a fly: + aArgs = { + comphelper::makePropertyValue("AnchorType", static_cast(0)), + }; + dispatchCommand(mxComponent, ".uno:InsertFrame", aArgs); + // Mark it as a floating table that wraps on all pages: + uno::Reference xTextFramesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xFrame( + xTextFramesSupplier->getTextFrames()->getByName("Frame1"), uno::UNO_QUERY); + xFrame->setPropertyValue("IsSplitAllowed", uno::Any(true)); + xFrame->setPropertyValue("WrapTextAtFlyStart", uno::Any(true)); + + // When saving to ODT: + save("writer8"); + + // Then make sure we write a floating table, that wraps on all pages: + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Without the accompanying fix in place, this test would have failed with: + // - XPath '//style:graphic-properties' no attribute 'wrap-text-at-frame-start' exist + // i.e. no floating table was exported. + assertXPath(pXmlDoc, "//style:graphic-properties"_ostr, "wrap-text-at-frame-start"_ostr, + "true"); +} + +CPPUNIT_TEST_FIXTURE(Test, testFloatingTableWrapTextAtFlyStartImport) +{ + // Given a document with a floating table + wrap on all pages + // (loext:may-break-between-pages="true" and loext:wrap-text-at-frame-start="true"), when + // importing that document: + loadFromFile(u"floattable-wrap-all-pages2.fodt"); + + // Then make sure that the matching text frame property is set: + uno::Reference xTextFramesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xFrame( + xTextFramesSupplier->getTextFrames()->getByName("Frame1"), uno::UNO_QUERY); + bool bWrapTextAtFlyStart = false; + // Without the accompanying fix in place, this test would have failed, the property was false. + xFrame->getPropertyValue("WrapTextAtFlyStart") >>= bWrapTextAtFlyStart; + CPPUNIT_ASSERT(bWrapTextAtFlyStart); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/qa/unit/tokenmap-test.cxx b/xmloff/qa/unit/tokenmap-test.cxx new file mode 100644 index 0000000000..395237b8ad --- /dev/null +++ b/xmloff/qa/unit/tokenmap-test.cxx @@ -0,0 +1,92 @@ +/* -*- 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 + +using namespace com::sun::star::uno; + +namespace xmloff { + +class TokenmapTest: public CppUnit::TestFixture +{ +public: + + TokenmapTest(); + + void test_roundTrip(); + void test_listEquality(); + + CPPUNIT_TEST_SUITE(TokenmapTest); + + CPPUNIT_TEST(test_roundTrip); + CPPUNIT_TEST(test_listEquality); + + CPPUNIT_TEST_SUITE_END(); + +private: + std::unique_ptr pTokenMap; +}; + +TokenmapTest::TokenmapTest() : pTokenMap(new token::TokenMap) +{ +} + +void TokenmapTest::test_roundTrip() +{ + for ( sal_Int32 nToken = 0; nToken < XML_TOKEN_COUNT; ++nToken ) + { + // check that the getIdentifier <-> getToken roundtrip works + Sequence< sal_Int8 > rUtf8Name = pTokenMap->getUtf8TokenName(nToken); + CPPUNIT_ASSERT_MESSAGE("Token name sequence should not be empty", rUtf8Name.getLength()); + const char* pChar = reinterpret_cast< const char * >(rUtf8Name.getConstArray()); + CPPUNIT_ASSERT_MESSAGE("Token name sequence array pointer failed", pChar); + sal_Int32 ret = token::TokenMap::getTokenFromUTF8( pChar, rUtf8Name.getLength() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("No roundtrip for token", ret, nToken); + } +} + +void TokenmapTest::test_listEquality() +{ + //make sure the two token lists stay in sync + // This depends on same order in three places: XMLTokenEnum in include/xmloff/xmltoken.hxx, + // aTokenList in xmloff/source/core/xmltoken.cxx, and xmloff/source/token/tokens.txt + for ( sal_Int32 nToken = 0; nToken < XML_TOKEN_COUNT; ++nToken ) + { + Sequence< sal_Int8 > rUtf8Name = pTokenMap->getUtf8TokenName(nToken); + const OUString& rName = OUString( reinterpret_cast< const char* >( + rUtf8Name.getConstArray() ), rUtf8Name.getLength(), RTL_TEXTENCODING_UTF8 ); + if ( rName.endsWith("_DUMMY") ) + continue; + const OUString& rTokenName = GetXMLToken( static_cast(nToken) ); + CPPUNIT_ASSERT_EQUAL(rName, rTokenName); + } + + for ( sal_Int32 nToken = xmloff::token::XMLTokenEnum::XML_TOKEN_START + 1; + nToken < xmloff::token::XMLTokenEnum::XML_TOKEN_END; ++nToken ) + { + const OUString& rTokenName = GetXMLToken( static_cast(nToken) ); + Sequence< sal_Int8 > rUtf8Name = pTokenMap->getUtf8TokenName(nToken); + const OUString& rName = OUString( reinterpret_cast< const char* >( + rUtf8Name.getConstArray() ), rUtf8Name.getLength(), RTL_TEXTENCODING_UTF8 ); + if ( !rName.endsWith("_DUMMY") ) + CPPUNIT_ASSERT_EQUAL(rTokenName, rName); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(TokenmapTest); + +} + diff --git a/xmloff/qa/unit/uxmloff.cxx b/xmloff/qa/unit/uxmloff.cxx new file mode 100644 index 0000000000..d87a3e86ee --- /dev/null +++ b/xmloff/qa/unit/uxmloff.cxx @@ -0,0 +1,233 @@ +/* -*- 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 + +using namespace ::xmloff::token; +using namespace ::com::sun::star; + +class Test : public test::BootstrapFixture { +public: + Test(); + + virtual void setUp() override; + virtual void tearDown() override; + + void testAutoStylePool(); + void testMetaGenerator(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testAutoStylePool); + CPPUNIT_TEST(testMetaGenerator); + CPPUNIT_TEST_SUITE_END(); +private: + rtl::Reference pExport; +}; + +Test::Test() +{ +} + +void Test::setUp() +{ + BootstrapFixture::setUp(); + + pExport = new SchXMLExport( + comphelper::getProcessComponentContext(), "SchXMLExport.Compact", + SvXMLExportFlags::ALL); +} + +void Test::tearDown() +{ + pExport.clear(); + BootstrapFixture::tearDown(); +} + +void Test::testAutoStylePool() +{ + rtl::Reference< SvXMLAutoStylePoolP > xPool( + new SvXMLAutoStylePoolP( *pExport ) ); + rtl::Reference< XMLPropertySetMapper > xSetMapper( + new XMLChartPropertySetMapper(pExport.get()) ); + rtl::Reference< XMLChartExportPropertyMapper > xExportPropMapper( + new XMLChartExportPropertyMapper( xSetMapper, *pExport ) ); + + xPool->AddFamily( XmlStyleFamily::TEXT_PARAGRAPH, + GetXMLToken( XML_PARAGRAPH ), + xExportPropMapper.get(), + OUString( "Bob" ) ); + + OUString aName = xPool->Add( XmlStyleFamily::TEXT_PARAGRAPH, "", {} ); + + // not that interesting but worth checking + bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr); + if (bHack) + CPPUNIT_ASSERT_EQUAL_MESSAGE( "style / naming changed", OUString("Bob"), aName ); + else + CPPUNIT_ASSERT_EQUAL_MESSAGE( "style / naming changed", OUString("Bob1"), aName ); + + // find ourselves again: + OUString aSameName = xPool->Find( XmlStyleFamily::TEXT_PARAGRAPH, "", {} ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "same style not found", aName, aSameName ); +} + +void Test::testMetaGenerator() +{ + comphelper::PropertyMapEntry const aInfoMap[] = { + { OUString("BuildId"), 0, ::cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0 }, + }; + uno::Reference const xInfoSet( + comphelper::GenericPropertySet_CreateInstance( + new comphelper::PropertySetInfo(aInfoMap))); + + static struct { + char const*const generator; + char const*const buildId; + sal_uInt16 const result; + } const tests [] = { + // foreign + { "AbiWord/2.8.6 (unix, gtk)", "", SvXMLImport::ProductVersionUnknown }, + { "Aspose.Words for Java 13.10.0.0", "", SvXMLImport::ProductVersionUnknown }, + { "CIB jsmerge 1.0.0", "", SvXMLImport::ProductVersionUnknown }, + { "Calligra/2.4.3", "", SvXMLImport::ProductVersionUnknown }, + { "CocoaODFWriter/1339", "", SvXMLImport::ProductVersionUnknown }, + { "KOffice/1.4.1", "", SvXMLImport::ProductVersionUnknown }, + { "KPresenter 1.3", "", SvXMLImport::ProductVersionUnknown }, + { "KSpread 1.3.2", "", SvXMLImport::ProductVersionUnknown }, + { "Lotus Symphony/1.2.0_20081023.1730/Win32", "", SvXMLImport::ProductVersionUnknown }, + { "Microsoft Excel Online", "", SvXMLImport::ProductVersionUnknown }, + { "MicrosoftOffice/12.0 MicrosoftExcel/CalculationVersion-4518", "", SvXMLImport::ProductVersionUnknown }, + { "MicrosoftOffice/15.0 MicrosoftWord", "", SvXMLImport::ProductVersionUnknown }, + { "ODF Converter v1.0.0", "", SvXMLImport::ProductVersionUnknown }, + { "ODF::lpOD 1.121", "", SvXMLImport::ProductVersionUnknown }, + { "ODFDOM/0.6.1$Build-1", "", SvXMLImport::ProductVersionUnknown }, + { "ODFPY/0.9.6", "", SvXMLImport::ProductVersionUnknown }, + { "OpenXML/ODF Translator Command Line Tool 3.0 2.0.0", "", SvXMLImport::ProductVersionUnknown }, + { "Org-7.8.03/Emacs-24.0.93.1", "", SvXMLImport::ProductVersionUnknown }, + { "TeX4ht from eqns_long.tex, options: xhtml,ooffice,refcaption", "", SvXMLImport::ProductVersionUnknown }, + { "TextMaker", "", SvXMLImport::ProductVersionUnknown }, + { "docbook2odf generator (http://open.comsultia.com/docbook2odf/)", "", SvXMLImport::ProductVersionUnknown }, + { "fig2sxd", "", SvXMLImport::ProductVersionUnknown }, + { "gnumeric/1.10.9", "", SvXMLImport::ProductVersionUnknown }, + { "libodfgen/0.1.6", "", SvXMLImport::ProductVersionUnknown }, + + // OOo 1.x + { "StarSuite 6.0 (Linux)", "645$8687", SvXMLImport::OOo_1x }, + { "StarOffice 6.1 (Win32)", "645$8687", SvXMLImport::OOo_1x }, + { "OpenOffice.org 1.1.2RC3.DE (Win32)", "645$8687", SvXMLImport::OOo_1x }, + { "OpenOffice.org 1.1.5 (Win32)", "645$8687", SvXMLImport::OOo_1x }, + { "StarOffice 7 (Win32)", "645$8687", SvXMLImport::OOo_1x }, + + // OOo 2.x + { "Sun_ODF_Plugin_for_Microsoft_Office/1.1$Win32 OpenOffice.org_project/680m5$Build-9221", "680$9221", SvXMLImport::OOo_2x }, + { "StarSuite/8$Win32 OpenOffice.org_project/680m6$Build-9095", "680$9095", SvXMLImport::OOo_2x }, + { "StarOffice/8$Win32 OpenOffice.org_project/680m93$Build-8897", "680$8897", SvXMLImport::OOo_2x }, + { "OpenOffice.org/2.0$Linux OpenOffice.org_project/680m3$Build-8968", "680$8968", SvXMLImport::OOo_2x }, + { "OpenOffice.org/2.1$Win32 OpenOffice.org_project/680m6$Build-9095", "680$9095", SvXMLImport::OOo_2x }, + { "OpenOffice.org/2.4$Win32 OpenOffice.org_project/680m248$Build-9274", "680$9274", SvXMLImport::OOo_2x }, + + // OOo 3.x + { "OpenOffice.org/3.0$Solaris_Sparc OpenOffice.org_project/300m9$Build-9358", "300$9358", SvXMLImport::OOo_30x }, + { "StarSuite/9$Unix OpenOffice.org_project/300m9$Build-9358", "300$9358", SvXMLImport::OOo_30x }, + { "StarOffice/9$Win32 OpenOffice.org_project/300m14$Build-9376", "300$9376", SvXMLImport::OOo_30x }, + { "OpenOffice.org/3.1$Solaris_x86 OpenOffice.org_project/310m11$Build-9399", "310$9399", SvXMLImport::OOo_31x }, + { "IBM_Lotus_Symphony/2.0$Win32 OpenOffice.org_project/310m11$Build-9399", "310$9399", SvXMLImport::OOo_31x }, + { "BrOffice.org/3.1$Linux OpenOffice.org_project/310m11$Build-9399", "310$9399", SvXMLImport::OOo_31x }, + { "StarOffice/9$Solaris_Sparc OpenOffice.org_project/310m19$Build-9420", "310$9420", SvXMLImport::OOo_31x }, + { "OpenOffice.org/3.2$Linux OpenOffice.org_project/320m12$Build-9483", "320$9483", SvXMLImport::OOo_32x }, + { "StarOffice/9$Win32 OpenOffice.org_project/320m12$Build-9483", "320$9483", SvXMLImport::OOo_32x }, + { "OpenOffice.org/3.3$Linux OpenOffice.org_project/330m20$Build-9567", "330$9567", SvXMLImport::OOo_33x }, + { "Oracle_Open_Office/3.3$Win32 OpenOffice.org_project/330m7$Build-9552", "330$9552", SvXMLImport::OOo_33x }, + { "OpenOffice.org/3.4$Unix OpenOffice.org_project/340m1$Build-9590", "340$9590", SvXMLImport::OOo_34x }, + + // AOO versions + { "OpenOffice/4.0.0$Win32 OpenOffice.org_project/400m3$Build-9702", "400$9702", SvXMLImport::AOO_40x }, + { "OpenOffice/4.0.1$Linux OpenOffice.org_project/401m4$Build-9713", "401$9713", SvXMLImport::AOO_40x }, + { "OpenOffice/4.1.1$FreeBSD/amd64 OpenOffice.org_project/411m6$Build-9775", "411$9775", SvXMLImport::AOO_4x }, + { "OpenOffice/4.1.2$OS/2 OpenOffice.org_project/412m3$Build-9782-bww", "412$9782-bww", SvXMLImport::AOO_4x }, + { "OpenOffice/4.1.4$Unix OpenOffice.org_project/414m2$Build-9785", "414$9785", SvXMLImport::AOO_4x }, + + // LO versions + { "LibreOffice/3.3$Linux LibreOffice_project/330m17$Build-3", "330$3;3.3", SvXMLImport::LO_3x }, + { "BrOffice/3.3$Win32 LibreOffice_project/330m19$Build-8", "330$8;3.3", SvXMLImport::LO_3x }, + { "LibreOffice/3.4$Linux LibreOffice_project/340m1$Build-1206", "340$1206;3.4", SvXMLImport::LO_3x }, + { "LibreOffice/3.5$Linux_X86_64 LibreOffice_project/3fa2330-e49ffd2-90d118b-705e248-051e21c", ";3.5", SvXMLImport::LO_3x }, + { "LibreOffice/3.6$Windows_x86 LibreOffice_project/a9a0717-273e462-768e6e3-978247f-65e65f", ";3.6", SvXMLImport::LO_3x }, + { "LibreOffice/4.0.2.2$Windows_x86 LibreOffice_project/4c82dcdd6efcd48b1d8bba66bfe1989deee49c3", ";4.0.2.2", SvXMLImport::LO_41x }, + { "LibreOffice/4.1.2.3$MacOSX_x86 LibreOffice_project/40b2d7fde7e8d2d7bc5a449dc65df4d08a7dd38", ";4.1.2.3", SvXMLImport::LO_41x }, + { "LibreOffice/4.2.8.2$Windows_x86 LibreOffice_project/48d50dbfc06349262c9d50868e5c1f630a573ebd", ";4.2.8.2", SvXMLImport::LO_42x }, + { "LibreOffice_from_Collabora_4.2-8/4.2.10.8$Linux_x86 LibreOffice_project/84584cc237b2eb93f7684d8fcd063bb37e87b5fb", ";4.2.10.8", SvXMLImport::LO_42x }, + { "LibreOffice/4.3.3.2$Linux_x86 LibreOffice_project/9bb7eadab57b6755b1265afa86e04bf45fbfc644", ";4.3.3.2", SvXMLImport::LO_43x }, + { "LibreOffice_from_Collabora_4.4-10/4.4.10.9$Linux_x86 LibreOffice_project/5600b19b88a01bbb669b0900100760758dff8c26", ";4.4.10.9", SvXMLImport::LO_44x }, + { "LibreOffice/4.3.3.2$Linux_X86_64 LibreOffice_project/430m0$Build-2", "430$2;4.3.3.2", SvXMLImport::LO_43x }, + { "LibreOffice/4.4.3.2$Linux_x86 LibreOffice_project/88805f81e9fe61362df02b9941de8e38a9b5fd16", ";4.4.3.2", SvXMLImport::LO_44x }, + { "LibreOffice/5.0.1.1$Linux_x86 LibreOffice_project/00m0$Build-1", "00$1;5.0.1.1", SvXMLImport::LO_5x }, + { "LibreOffice/5.0.3.2$Windows_X86_64 LibreOffice_project/e5f16313668ac592c1bfb310f4390624e3dbfb75", ";5.0.3.2", SvXMLImport::LO_5x }, + { "Collabora_Office/5.0.10.19$Linux_X86_64 LibreOffice_project/95060d44300d8866fa81c16fc8fe2afe22d63777", ";5.0.10.19", SvXMLImport::LO_5x }, + { "LibreOffice/5.1.6.2.0$Linux_X86_64 LibreOffice_project/10$Build-2", ";5.1.6.2.0", SvXMLImport::LO_5x }, + { "Collabora_Office/5.1.10.17$Linux_X86_64 LibreOffice_project/a104cbe76eefca3cf23973da68893d2225fd718b", ";5.1.10.17", SvXMLImport::LO_5x }, + { "LibreOffice/5.2.1.2$Windows_X86_64 LibreOffice_project/31dd62db80d4e60af04904455ec9c9219178d620", ";5.2.1.2", SvXMLImport::LO_5x }, + { "LibreOffice_Vanilla/5.2.3.5$MacOSX_X86_64 LibreOffice_project/83adc9c35c74e0badc710d981405858b1179a327", ";5.2.3.5", SvXMLImport::LO_5x }, + { "LibreOffice/5.3.4.2$Windows_X86_64 LibreOffice_project/f82d347ccc0be322489bf7da61d7e4ad13fe2ff3", ";5.3.4.2", SvXMLImport::LO_5x }, + { "Collabora_Office/5.3.10.27$Linux_X86_64 LibreOffice_project/7a5a5378661e338a44666c08773cc796b8d1c84a", ";5.3.10.27", SvXMLImport::LO_5x }, + { "LibreOfficeDev/5.4.7.0.0$Linux_X86_64 LibreOffice_project/ba7461fc88c08e75e315f786020a2946e56166c9", ";5.4.7.0.0", SvXMLImport::LO_5x }, + { "LibreOfficeDev/6.0.3.0.0$Linux_X86_64 LibreOffice_project/34442b85bfb0c451738b4db023345a7484463321", ";6.0.3.0.0", SvXMLImport::LO_6x }, + { "LibreOffice_powered_by_CIBDev/6.3.9.0.0$Linux_X86_64 LibreOffice_project/c87f331d2900eab70ac3021cbe530926efa6499f", ";6.3.9.0.0", SvXMLImport::LO_63x }, + { "LibreOffice_powered_by_CIBDev/6.4.0.0.0$Linux_X86_64 LibreOffice_project/e29e100174c133d27e953934311d68602c4515b7", ";6.4.0.0.0", SvXMLImport::LO_63x }, + { "LibreOfficeDev/7.0.6.0.0$Linux_X86_64 LibreOffice_project/dfc40e2292c6e19e285c10ed8c8044d9454107d0", ";7.0.6.0.0", SvXMLImport::LO_7x }, + { "CIB_OfficeDev/6.4.0.19$Linux_X86_64 LibreOffice_project/2e04f804b5f82770435f250873f07b3384d95504", ";6.4.0.19", SvXMLImport::LO_63x }, + { "LibreOfficeDev/24.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/b81e7b6f3c71fb3ade1cb665444ac730dac0a9a9", ";24.2.0.0.", SvXMLImport::LO_New }, + }; + + for (auto const[pGenerator, pBuildId, nResult] : tests) + { + // the DocumentInfo instance is cached so need fresh SvXMLImport + rtl::Reference const pImport(new SvXMLImport( + comphelper::getProcessComponentContext(), "testdummy", + SvXMLImportFlags::ALL)); + + pImport->initialize(uno::Sequence{ uno::Any(xInfoSet) }); + + SvXMLMetaDocumentContext::setBuildId(OUString::createFromAscii(pGenerator), xInfoSet); + if (pBuildId[0] != '\0') + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(pGenerator, + OUString::createFromAscii(pBuildId), + xInfoSet->getPropertyValue("BuildId").get()); + } + else + { + CPPUNIT_ASSERT_MESSAGE(pGenerator, !xInfoSet->getPropertyValue("BuildId").hasValue()); + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(pGenerator, nResult, pImport->getGeneratorVersion()); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3